如何在 Java 中检查列表是否包含重复元素

JavaJavaBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在这个实验中,你将学习如何高效地检查 Java List 中是否包含重复元素。我们将探索一种使用 HashSet 数据结构的常见且有效的技术。

你将首先实现一个方法,该方法利用 HashSet 的元素唯一性特性,通过遍历列表并将元素添加到集合中来检测重复项。如果某个元素已经存在于集合中,则表示找到了重复项。随后,你将学习另一种方法,即比较原始列表的大小与用列表元素填充的 HashSet 的大小。最后,你将使用各种场景(包括空列表和 null 列表)来测试你的实现,以确保其健壮性。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL java(("Java")) -.-> java/DataStructuresGroup(["Data Structures"]) java(("Java")) -.-> java/ObjectOrientedandAdvancedConceptsGroup(["Object-Oriented and Advanced Concepts"]) java/DataStructuresGroup -.-> java/arrays("Arrays") java/DataStructuresGroup -.-> java/collections_methods("Collections Methods") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/arraylist("ArrayList") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/hashset("HashSet") subgraph Lab Skills java/arrays -.-> lab-559948{{"如何在 Java 中检查列表是否包含重复元素"}} java/collections_methods -.-> lab-559948{{"如何在 Java 中检查列表是否包含重复元素"}} java/arraylist -.-> lab-559948{{"如何在 Java 中检查列表是否包含重复元素"}} java/hashset -.-> lab-559948{{"如何在 Java 中检查列表是否包含重复元素"}} end

使用 HashSet 进行重复项检测

在这一步中,我们将探讨如何在 Java 中使用 HashSet 来高效地检测集合中的重复元素。HashSet 是 Java 集合框架(Java Collections Framework)的一部分,特别适用于存储唯一元素。

首先,在你的 ~/project 目录下创建一个名为 DuplicateDetector.java 的新 Java 文件。你可以使用左侧 WebIDE 的文件资源管理器来完成此操作。在 ~/project 区域右键单击,选择“新建文件”,然后输入 DuplicateDetector.java

现在,在代码编辑器中打开 DuplicateDetector.java 文件,并添加以下代码:

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class DuplicateDetector {

    public static boolean containsDuplicates(List<String> list) {
        // Create a HashSet to store unique elements
        Set<String> uniqueElements = new HashSet<>();

        // Iterate through the list
        for (String element : list) {
            // If the element is already in the HashSet, it's a duplicate
            if (uniqueElements.contains(element)) {
                return true; // Found a duplicate
            }
            // Otherwise, add the element to the HashSet
            uniqueElements.add(element);
        }

        // If the loop finishes without finding duplicates, return false
        return false;
    }

    public static void main(String[] args) {
        // Example usage
        List<String> myListWithDuplicates = new ArrayList<>();
        myListWithDuplicates.add("apple");
        myListWithDuplicates.add("banana");
        myListWithDuplicates.add("apple"); // Duplicate
        myListWithDuplicates.add("orange");

        List<String> myListWithoutDuplicates = new ArrayList<>();
        myListWithoutDuplicates.add("grape");
        myListWithoutDuplicates.add("mango");
        myListWithoutDuplicates.add("kiwi");

        System.out.println("List with duplicates: " + myListWithDuplicates);
        System.out.println("Contains duplicates? " + containsDuplicates(myListWithDuplicates)); // Expected: true

        System.out.println("\nList without duplicates: " + myListWithoutDuplicates);
        System.out.println("Contains duplicates? " + containsDuplicates(myListWithoutDuplicates)); // Expected: false
    }
}

让我们来理解这段代码的关键部分:

  • import java.util.ArrayList;import java.util.HashSet;import java.util.List;import java.util.Set;:这些行从 Java 集合框架中导入了必要的类。
  • public static boolean containsDuplicates(List<String> list):这是一个方法,它接受一个 String 对象的 List 作为输入,如果列表包含重复项,则返回 true,否则返回 false
  • Set<String> uniqueElements = new HashSet<>();:这行代码创建了一个名为 uniqueElements 的空 HashSetHashSet 被设计为只存储唯一元素。
  • for (String element : list):这个循环遍历输入 list 中的每个 element
  • if (uniqueElements.contains(element)):这行代码检查当前 element 是否已经存在于 uniqueElements HashSet 中。如果存在,意味着我们找到了一个重复项,该方法返回 true
  • uniqueElements.add(element);:如果元素还不在 HashSet 中,则将其添加进去。由于 HashSet 只存储唯一元素,添加已经存在的元素不会产生任何效果。
  • return false;:如果循环结束后没有找到任何重复项,该方法返回 false
  • main 方法展示了如何使用 containsDuplicates 方法处理示例列表。

保存 DuplicateDetector.java 文件(Ctrl+S 或 Cmd+S)。

现在,让我们在终端中编译并运行这个程序。确保你位于 ~/project 目录下。

编译代码:

javac DuplicateDetector.java

如果没有编译错误,你将看不到任何输出。

现在,运行编译后的代码:

java DuplicateDetector

你应该会看到类似于以下的输出:

List with duplicates: [apple, banana, apple, orange]
Contains duplicates? true

List without duplicates: [grape, mango, kiwi]
Contains duplicates? false

这个输出证实了我们的 containsDuplicates 方法正确地识别出了包含重复项的列表。使用 HashSet 是一种高效的检查重复项的方法,因为平均而言,在 HashSet 中检查元素是否存在(使用 contains() 方法)的速度非常快。

比较列表大小和集合大小

在上一步中,我们通过遍历列表并将元素添加到 HashSet 中来检查重复项。一种更简单且通常更高效的检测重复项的方法是比较原始列表的大小和从该列表创建的 HashSet 的大小。

请记住,HashSet 只存储唯一元素。如果列表包含重复项,那么从该列表创建的 HashSet 的大小将小于原始列表的大小。如果没有重复项,两者的大小将相同。

让我们修改 DuplicateDetector.java 文件来实现这种方法。在代码编辑器中打开 ~/project/DuplicateDetector.java

containsDuplicates 方法替换为以下代码:

    public static boolean containsDuplicates(List<String> list) {
        // Create a HashSet from the list
        Set<String> uniqueElements = new HashSet<>(list);

        // Compare the size of the list with the size of the HashSet
        return list.size() != uniqueElements.size();
    }

以下是新代码的工作原理:

  • Set<String> uniqueElements = new HashSet<>(list);:这行代码直接创建一个 HashSet,并使用输入 list 中的所有元素对其进行初始化。HashSet 会自动处理唯一性,因此列表中的任何重复元素都不会被添加到集合中。
  • return list.size() != uniqueElements.size();:这行代码比较原始 list 中的元素数量(list.size())和 HashSet 中的唯一元素数量(uniqueElements.size())。如果大小不同(!=),则意味着列表中存在重复项,该方法返回 true。如果大小相同,则表示没有重复项,该方法返回 false

main 方法可以保持不变,因为它已经调用了 containsDuplicates 方法。

保存 DuplicateDetector.java 文件(Ctrl+S 或 Cmd+S)。

现在,让我们编译并运行修改后的程序。确保你在终端中位于 ~/project 目录下。

编译代码:

javac DuplicateDetector.java

运行编译后的代码:

java DuplicateDetector

你应该会看到与之前相同的输出:

List with duplicates: [apple, banana, apple, orange]
Contains duplicates? true

List without duplicates: [grape, mango, kiwi]
Contains duplicates? false

这证实了我们使用大小比较来检测重复项的新的、更简单的方法是正确的。这种方法通常更简洁,并且在处理较大列表时,通常比逐个迭代和检查元素是否存在更高效。

对空列表和 null 列表进行测试

在实际编程中,考虑边界情况非常重要,例如列表为空甚至为 null 的情况。我们当前的 containsDuplicates 方法对于包含元素的列表效果很好,但如果传入一个空列表或 null 列表会发生什么呢?

让我们通过在 ~/project/DuplicateDetector.javamain 方法中添加更多示例来测试这一点。在代码编辑器中打开该文件,并在现有代码之后的 main 方法中添加以下行:

        System.out.println("\nEmpty list: " + new ArrayList<>());
        System.out.println("Contains duplicates? " + containsDuplicates(new ArrayList<>())); // Expected: false

        List<String> nullList = null;
        System.out.println("\nNull list: " + nullList);
        // The following line will cause a NullPointerException if not handled
        // System.out.println("Contains duplicates? " + containsDuplicates(nullList));

保存文件(Ctrl+S 或 Cmd+S)。

现在,再次编译并运行程序。

编译:

javac DuplicateDetector.java

运行:

java DuplicateDetector

你应该会看到空列表的输出:

List with duplicates: [apple, banana, apple, orange]
Contains duplicates? true

List without duplicates: [grape, mango, kiwi]
Contains duplicates? false

Empty list: []
Contains duplicates? false

空列表的输出是正确的;空列表不包含重复项。

然而,如果你取消注释行 System.out.println("Contains duplicates? " + containsDuplicates(nullList)); 并尝试编译和运行,你将得到一个 NullPointerException。这是因为我们试图从一个 null 列表创建一个 HashSet,这是不允许的。

为了让我们的 containsDuplicates 方法更健壮,我们应该处理输入列表为 null 的情况。我们可以在方法开始处添加一个检查。

修改 ~/project/DuplicateDetector.java 中的 containsDuplicates 方法,以包含空值检查:

    public static boolean containsDuplicates(List<String> list) {
        // Handle null input
        if (list == null) {
            return false; // A null list does not contain duplicates
        }

        // Create a HashSet from the list
        Set<String> uniqueElements = new HashSet<>(list);

        // Compare the size of the list with the size of the HashSet
        return list.size() != uniqueElements.size();
    }

现在,取消注释 main 方法中测试 null 列表的行:

        List<String> nullList = null;
        System.out.println("\nNull list: " + nullList);
        System.out.println("Contains duplicates? " + containsDuplicates(nullList)); // Expected: false

保存文件(Ctrl+S 或 Cmd+S)。

最后一次编译并运行程序。

编译:

javac DuplicateDetector.java

运行:

java DuplicateDetector

现在输出应该包含 null 列表的结果,并且不会崩溃:

List with duplicates: [apple, banana, apple, orange]
Contains duplicates? true

List without duplicates: [grape, mango, kiwi]
Contains duplicates? false

Empty list: []
Contains duplicates? false

Null list: null
Contains duplicates? false

通过添加空值检查,我们的 containsDuplicates 方法现在更健壮了,可以优雅地处理 null 输入。这是编程中防止意外错误的重要实践。

总结

在本次实验中,我们学习了如何检查 Java List 是否包含重复元素。我们探索了使用 HashSet 来高效检测重复项的方法。通过遍历列表并尝试将每个元素添加到 HashSet 中,我们可以快速判断某个元素是否已经存在,从而确定是否有重复项。

我们还学习了另一种方法,即比较原始列表的大小和从该列表创建的 HashSet 的大小。如果大小不同,则表明存在重复项。最后,我们通过使用空列表和 null 列表对这些方法进行测试,考虑了边界情况,以确保方法的健壮性。