如何在 Java 中检查一个列表是否包含另一个列表的所有元素

JavaJavaBeginner
立即练习

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

简介

在这个实验中,你将学习如何在 Java 中检查一个列表是否包含另一个列表的所有元素。在处理集合以及理解数据集之间的关系时,这是一项基本任务。

我们将探索 Java 集合框架提供的高效 containsAll() 方法,用于快速进行子集检查。为了巩固你的理解,你还将学习如何使用循环手动执行此检查。最后,我们将使用边界情况(包括空列表和 null 列表)测试这些方法的行为,以确保代码的健壮性。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL java(("Java")) -.-> java/BasicSyntaxGroup(["Basic Syntax"]) java(("Java")) -.-> java/DataStructuresGroup(["Data Structures"]) java(("Java")) -.-> java/ObjectOrientedandAdvancedConceptsGroup(["Object-Oriented and Advanced Concepts"]) java/BasicSyntaxGroup -.-> java/for_loop("For Loop") java/DataStructuresGroup -.-> java/arrays_methods("Arrays Methods") java/DataStructuresGroup -.-> java/collections_methods("Collections Methods") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/classes_objects("Classes/Objects") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/arraylist("ArrayList") subgraph Lab Skills java/for_loop -.-> lab-559946{{"如何在 Java 中检查一个列表是否包含另一个列表的所有元素"}} java/arrays_methods -.-> lab-559946{{"如何在 Java 中检查一个列表是否包含另一个列表的所有元素"}} java/collections_methods -.-> lab-559946{{"如何在 Java 中检查一个列表是否包含另一个列表的所有元素"}} java/classes_objects -.-> lab-559946{{"如何在 Java 中检查一个列表是否包含另一个列表的所有元素"}} java/arraylist -.-> lab-559946{{"如何在 Java 中检查一个列表是否包含另一个列表的所有元素"}} end

使用 containsAll() 进行子集检查

在这一步中,我们将探讨如何使用 Java 中的 containsAll() 方法来检查一个列表是否是另一个列表的子集。在处理集合时,这是一项常见任务,而 containsAll() 提供了一种便捷的方式来执行此检查。

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

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

import java.util.ArrayList;
import java.util.List;

public class SubsetCheck {

    public static void main(String[] args) {
        // Create the main list
        List<String> mainList = new ArrayList<>();
        mainList.add("Apple");
        mainList.add("Banana");
        mainList.add("Cherry");
        mainList.add("Date");

        // Create a potential subset list
        List<String> subList = new ArrayList<>();
        subList.add("Banana");
        subList.add("Cherry");

        // Check if subList is a subset of mainList using containsAll()
        boolean isSubset = mainList.containsAll(subList);

        // Print the result
        System.out.println("Main List: " + mainList);
        System.out.println("Sub List: " + subList);
        System.out.println("Is subList a subset of mainList? " + isSubset);

        // Create another list that is not a subset
        List<String> anotherList = new ArrayList<>();
        anotherList.add("Banana");
        anotherList.add("Grape"); // Grape is not in mainList

        // Check if anotherList is a subset of mainList
        boolean isAnotherSubset = mainList.containsAll(anotherList);

        // Print the result for the second check
        System.out.println("\nAnother List: " + anotherList);
        System.out.println("Is anotherList a subset of mainList? " + isAnotherSubset);
    }
}

让我们来分析一下这段代码:

  • 我们从 java.util 包中导入 ArrayListList 以处理列表。
  • 我们创建了两个 ArrayList 对象:mainListsubList
  • 我们向两个列表中添加了一些字符串元素。
  • 关键部分是 mainList.containsAll(subList)。此方法检查 mainList 是否包含 subList 中的所有元素。如果包含,则返回 true,否则返回 false
  • 我们将结果存储在布尔变量 isSubset 中并打印出来。
  • 然后,我们创建了 anotherList,其中包含一个 mainList 中不存在的元素,并执行相同的检查,以查看当它不是子集时的结果。

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

现在,打开 WebIDE 底部的终端。确保你位于 ~/project 目录中。如果不在,请使用命令 cd ~/project

使用 javac 命令编译 Java 代码:

javac SubsetCheck.java

如果没有编译错误,你应该会看到 ~/project 目录中创建了一个 SubsetCheck.class 文件。

最后,使用 java 命令运行编译后的 Java 程序:

java SubsetCheck

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

Main List: [Apple, Banana, Cherry, Date]
Sub List: [Banana, Cherry]
Is subList a subset of mainList? true

Another List: [Banana, Grape]
Is anotherList a subset of mainList? false

此输出证实了 subList 确实是 mainList 的子集,因为它的所有元素都存在于 mainList 中,而 anotherList 不是子集,因为“Grape”不在 mainList 中。

使用手动循环进行验证

在上一步中,我们使用了便捷的 containsAll() 方法来检查子集。虽然 containsAll() 方法很高效,但了解如何使用循环手动执行此检查会很有帮助。这将加深你对集合方法内部工作原理的理解。

让我们在 SubsetCheck.java 文件中添加一个新方法,以手动执行子集检查。在 WebIDE 编辑器中打开 ~/project/SubsetCheck.java 文件。

SubsetCheck 类内部,但在 main 方法外部添加以下方法:

    // Method to manually check if subList is a subset of mainList
    public static boolean isSubsetManual(List<String> mainList, List<String> subList) {
        // Iterate through each element in the subList
        for (String element : subList) {
            // If the mainList does NOT contain the current element from subList,
            // then subList is not a subset, and we can return false immediately.
            if (!mainList.contains(element)) {
                return false;
            }
        }
        // If we have checked all elements in subList and found them all in mainList,
        // then subList is a subset.
        return true;
    }

这个新方法 isSubsetManual 接受两个列表作为输入。然后,它会遍历 subList 中的每个 element。在循环内部,它使用 contains() 方法检查 mainList 是否包含当前的 element。如果在 subList 中发现哪怕有一个元素不在 mainList 中,它就会立即判定 subList 不是子集,并返回 false。如果循环结束后,没有发现 subList 中有任何元素不在 mainList 中,就意味着所有元素都存在,该方法将返回 true

现在,让我们从 main 方法中调用这个新方法,将其结果与 containsAll() 的结果进行比较。修改 SubsetCheck.java 中的 main 方法,以包含对 isSubsetManual 的调用:

import java.util.ArrayList;
import java.util.List;

public class SubsetCheck {

    public static void main(String[] args) {
        // Create the main list
        List<String> mainList = new ArrayList<>();
        mainList.add("Apple");
        mainList.add("Banana");
        mainList.add("Cherry");
        mainList.add("Date");

        // Create a potential subset list
        List<String> subList = new ArrayList<>();
        subList.add("Banana");
        subList.add("Cherry");

        // Check if subList is a subset of mainList using containsAll()
        boolean isSubsetContainsAll = mainList.containsAll(subList);
        // Check if subList is a subset of mainList using manual loop
        boolean isSubsetManualCheck = isSubsetManual(mainList, subList);


        // Print the result
        System.out.println("Main List: " + mainList);
        System.out.println("Sub List: " + subList);
        System.out.println("Is subList a subset of mainList (containsAll)? " + isSubsetContainsAll);
        System.out.println("Is subList a subset of mainList (manual check)? " + isSubsetManualCheck);


        // Create another list that is not a subset
        List<String> anotherList = new ArrayList<>();
        anotherList.add("Banana");
        anotherList.add("Grape"); // Grape is not in mainList

        // Check if anotherList is a subset of mainList using containsAll()
        boolean isAnotherSubsetContainsAll = mainList.containsAll(anotherList);
         // Check if anotherList is a subset of mainList using manual loop
        boolean isAnotherSubsetManualCheck = isSubsetManual(mainList, anotherList);


        // Print the result for the second check
        System.out.println("\nAnother List: " + anotherList);
        System.out.println("Is anotherList a subset of mainList (containsAll)? " + isAnotherSubsetContainsAll);
        System.out.println("Is anotherList a subset of mainList (manual check)? " + isAnotherSubsetManualCheck);

    }

    // Method to manually check if subList is a subset of mainList
    public static boolean isSubsetManual(List<String> mainList, List<String> subList) {
        // Iterate through each element in the subList
        for (String element : subList) {
            // If the mainList does NOT contain the current element from subList,
            // then subList is not a subset, and we can return false immediately.
            if (!mainList.contains(element)) {
                return false;
            }
        }
        // If we have checked all elements in subList and found them all in mainList,
        // then subList is a subset.
        return true;
    }
}

保存修改后的 SubsetCheck.java 文件。

现在,在终端中编译更新后的代码:

javac SubsetCheck.java

然后再次运行程序:

java SubsetCheck

你应该会看到类似以下的输出,表明 containsAll() 方法和我们的手动循环方法产生了相同的结果:

Main List: [Apple, Banana, Cherry, Date]
Sub List: [Banana, Cherry]
Is subList a subset of mainList (containsAll)? true
Is subList a subset of mainList (manual check)? true

Another List: [Banana, Grape]
Is anotherList a subset of mainList (containsAll)? false
Is anotherList a subset of mainList (manual check)? false

这一步表明,通过遍历潜在的子集并检查每个元素是否存在于主列表中,你可以获得与 containsAll() 相同的结果。虽然由于 containsAll() 的简洁性以及 Java 库中可能的性能优化,它通常是首选方法,但理解手动实现的方法对于学习来说是很有价值的。

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

在这一步中,我们将探讨 containsAll() 方法和我们的手动检查方法在处理空列表和 null 值时的表现。理解这些边界情况对于编写健壮的代码至关重要。

在 WebIDE 编辑器中打开 ~/project/SubsetCheck.java 文件。我们将在 main 方法中添加更多测试用例。

修改 main 方法,以包含对空列表和 null 列表的检查:

import java.util.ArrayList;
import java.util.List;

public class SubsetCheck {

    public static void main(String[] args) {
        // Create the main list
        List<String> mainList = new ArrayList<>();
        mainList.add("Apple");
        mainList.add("Banana");
        mainList.add("Cherry");
        mainList.add("Date");

        // Create a potential subset list
        List<String> subList = new ArrayList<>();
        subList.add("Banana");
        subList.add("Cherry");

        // Check if subList is a subset of mainList using containsAll()
        boolean isSubsetContainsAll = mainList.containsAll(subList);
        // Check if subList is a subset of mainList using manual loop
        boolean isSubsetManualCheck = isSubsetManual(mainList, subList);


        // Print the result
        System.out.println("Main List: " + mainList);
        System.out.println("Sub List: " + subList);
        System.out.println("Is subList a subset of mainList (containsAll)? " + isSubsetContainsAll);
        System.out.println("Is subList a subset of mainList (manual check)? " + isSubsetManualCheck);


        // Create another list that is not a subset
        List<String> anotherList = new ArrayList<>();
        anotherList.add("Banana");
        anotherList.add("Grape"); // Grape is not in mainList

        // Check if anotherList is a subset of mainList using containsAll()
        boolean isAnotherSubsetContainsAll = mainList.containsAll(anotherList);
         // Check if anotherList is a subset of mainList using manual loop
        boolean isAnotherSubsetManualCheck = isSubsetManual(mainList, anotherList);


        // Print the result for the second check
        System.out.println("\nAnother List: " + anotherList);
        System.out.println("Is anotherList a subset of mainList (containsAll)? " + isAnotherSubsetContainsAll);
        System.out.println("Is anotherList a subset of mainList (manual check)? " + isAnotherSubsetManualCheck);

        // --- Test with Empty Lists ---

        // Create an empty list
        List<String> emptyList = new ArrayList<>();

        // Check if emptyList is a subset of mainList
        boolean isEmptySubsetContainsAll = mainList.containsAll(emptyList);
        boolean isEmptySubsetManualCheck = isSubsetManual(mainList, emptyList);

        System.out.println("\nEmpty List: " + emptyList);
        System.out.println("Is emptyList a subset of mainList (containsAll)? " + isEmptySubsetContainsAll);
        System.out.println("Is emptyList a subset of mainList (manual check)? " + isEmptySubsetManualCheck);

        // Check if mainList is a subset of emptyList (should be false unless mainList is also empty)
        boolean isMainSubsetEmptyContainsAll = emptyList.containsAll(mainList);
        boolean isMainSubsetEmptyManualCheck = isSubsetManual(emptyList, mainList);

        System.out.println("Is mainList a subset of emptyList (containsAll)? " + isMainSubsetEmptyContainsAll);
        System.out.println("Is mainList a subset of emptyList (manual check)? " + isMainSubsetEmptyManualCheck);

        // --- Test with Null List ---

        // Create a null list
        List<String> nullList = null;

        // Check with nullList using containsAll()
        System.out.println("\nNull List: " + nullList);
        try {
            boolean isNullSubsetContainsAll = mainList.containsAll(nullList);
            System.out.println("Is nullList a subset of mainList (containsAll)? " + isNullSubsetContainsAll);
        } catch (NullPointerException e) {
            System.out.println("Checking with nullList using containsAll() resulted in: " + e);
        }

        // Check with nullList using manual loop
         try {
            boolean isNullSubsetManualCheck = isSubsetManual(mainList, nullList);
            System.out.println("Is nullList a subset of mainList (manual check)? " + isNullSubsetManualCheck);
        } catch (NullPointerException e) {
            System.out.println("Checking with nullList using manual check resulted in: " + e);
        }
    }

    // Method to manually check if subList is a subset of mainList
    public static boolean isSubsetManual(List<String> mainList, List<String> subList) {
        // Add a check for null subList in the manual method
        if (subList == null) {
             throw new NullPointerException("Sub list cannot be null for manual check.");
        }
        // Iterate through each element in the subList
        for (String element : subList) {
            // If the mainList does NOT contain the current element from subList,
            // then subList is not a subset, and we can return false immediately.
            if (!mainList.contains(element)) {
                return false;
            }
        }
        // If we have checked all elements in subList and found them all in mainList,
        // then subList is a subset.
        return true;
    }
}

我们添加了对 emptyListnullList 进行测试的部分。注意,在对 nullList 进行测试时,我们将调用语句包裹在 try-catch 块中。这是因为尝试对 null 对象调用方法(如 mainList.containsAll(nullList))会导致 NullPointerException。我们的手动方法也需要处理 subListnull 的情况,因此我们在 isSubsetManual 方法的开头添加了一个检查。

保存修改后的 SubsetCheck.java 文件。

在终端中编译更新后的代码:

javac SubsetCheck.java

然后再次运行程序:

java SubsetCheck

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

Main List: [Apple, Banana, Cherry, Date]
Sub List: [Banana, Cherry]
Is subList a subset of mainList (containsAll)? true
Is subList a subset of mainList (manual check)? true

Another List: [Banana, Grape]
Is anotherList a subset of mainList (containsAll)? false
Is anotherList a subset of mainList (manual check)? false

Empty List: []
Is emptyList a subset of mainList (containsAll)? true
Is emptyList a subset of mainList (manual check)? true
Is mainList a subset of emptyList (containsAll)? false
Is mainList a subset of emptyList (manual check)? false

Null List: null
Checking with nullList using containsAll() resulted in: java.lang.NullPointerException
Checking with nullList using manual check resulted in: java.lang.NullPointerException: Sub list cannot be null for manual check.

从输出中可以观察到以下几点:

  • 空列表被视为任何列表(包括另一个空列表)的子集。containsAll() 方法和我们的手动方法都能正确识别这一点。
  • 非空列表不是空列表的子集。
  • null 列表传递给 containsAll() 方法或我们的手动方法(未进行空值检查)会导致 NullPointerException。这凸显了在代码中处理潜在 null 值的重要性。

这一步结束了我们对 Java 列表中子集检查的探索。你已经学会了如何使用内置的 containsAll() 方法、如何手动进行检查,以及这些方法在处理空列表和 null 列表时的表现。

总结

在这个实验中,我们学习了如何在 Java 中检查一个列表是否包含另一个列表的所有元素。我们主要关注使用 Collection 接口提供的便捷 containsAll() 方法。

我们通过示例列表演示了如何使用 containsAll() 方法,并观察了它在子集和非子集情况下的表现。该方法为执行这种常见的列表比较任务提供了一种简洁而高效的方式。