介绍
在这个实验中,你将学习如何高效地检查 Java 集合中是否存在重复元素。我们将探索使用 HashSet(Java 集合框架中的一个强大工具)来识别重复元素。
通过实际操作步骤,你将首先学习如何利用 HashSet 的元素唯一性特性来检测重复元素。然后,你将发现另一种方法,即比较原始集合和由其创建的 HashSet 的大小。最后,我们将探讨在检查重复元素时如何处理空元素。
使用 HashSet 进行重复元素检查
在这一步中,我们将探索如何在 Java 中使用 HashSet 来高效地检查集合中是否存在重复元素。HashSet 是 Java 集合框架的一部分,它特别有用,因为它存储唯一元素,并且查找速度非常快。
首先,在你的 ~/project 目录下创建一个名为 DuplicateCheck.java 的新 Java 文件。你可以直接在 WebIDE 文件资源管理器中,右键单击文件列表区域,选择“新建文件”,然后输入 DuplicateCheck.java 来完成此操作。
现在,在代码编辑器中打开 DuplicateCheck.java 文件,并添加以下代码:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DuplicateCheck {
public static void main(String[] args) {
// Create a list with some duplicate elements
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Alice"); // Duplicate
names.add("Charlie");
names.add("Bob"); // Duplicate
System.out.println("Original List: " + names);
// Use a HashSet to find duplicates
Set<String> uniqueNames = new HashSet<>();
Set<String> duplicates = new HashSet<>();
for (String name : names) {
if (!uniqueNames.add(name)) {
// If add returns false, the element is already in the set
duplicates.add(name);
}
}
System.out.println("Duplicates found: " + duplicates);
}
}
让我们来详细分析这段代码的新部分:
import java.util.ArrayList;、import java.util.HashSet;、import java.util.List;、import java.util.Set;:这些行从 Java 实用工具库中导入了处理列表和集合所需的类。List<String> names = new ArrayList<>();:这行代码创建了一个名为names的List,它可以存储String对象。我们使用ArrayList作为List接口的具体实现。names.add(...):这行代码向我们的names列表中添加元素。注意,"Alice" 和 "Bob" 被添加了两次。Set<String> uniqueNames = new HashSet<>();:这行代码使用HashSet实现创建了一个名为uniqueNames的Set。Set保证只包含唯一元素。Set<String> duplicates = new HashSet<>();:这行代码创建了另一个Set,用于存储我们找到的重复元素。for (String name : names):这是一个for-each循环,用于遍历names列表中的每个name。if (!uniqueNames.add(name)):HashSet的add()方法在元素成功添加(即该元素不在集合中)时返回true,如果元素已经存在则返回false。!对结果取反,因此if块内的代码仅在add()返回false时执行,这表明存在重复元素。duplicates.add(name);:如果找到重复元素,我们将其添加到duplicates集合中。
保存 DuplicateCheck.java 文件(Ctrl + S 或 Cmd + S)。
现在,打开 WebIDE 底部的终端。确保你位于 ~/project 目录下。你可以通过输入 pwd 并按回车键来确认。输出应该是 /home/labex/project。
使用 javac 命令编译 Java 程序:
javac DuplicateCheck.java
如果没有错误,你应该看不到输出。这意味着编译成功,并且在 ~/project 目录下已经创建了一个 DuplicateCheck.class 文件。你可以通过运行 ls 命令来验证。
最后,使用 java 命令运行编译后的 Java 程序:
java DuplicateCheck
你应该会看到类似以下的输出:
Original List: [Alice, Bob, Alice, Charlie, Bob]
Duplicates found: [Alice, Bob]
Duplicates found 输出中的元素顺序可能会有所不同,因为 HashSet 不维护插入顺序。
你已经成功使用 HashSet 识别了列表中的重复元素!
比较集合和 Set 的大小
在上一步中,我们使用 HashSet 来查找重复元素。Set 的一个关键特性是它只存储唯一元素。这意味着,如果你向 Set 中添加重复元素,每个元素只会保留一个实例。这个特性在从列表中去除重复元素等任务中非常有用。
在这一步中,我们将修改 DuplicateCheck.java 程序,通过比较原始列表(可能包含重复元素)的大小和从该列表创建的 HashSet(只包含唯一元素)的大小,来展示这个特性。
在 WebIDE 代码编辑器中打开 DuplicateCheck.java 文件。
将 main 方法修改为如下所示:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DuplicateCheck {
public static void main(String[] args) {
// Create a list with some duplicate elements
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Alice"); // Duplicate
names.add("Charlie");
names.add("Bob"); // Duplicate
names.add("David");
System.out.println("Original List: " + names);
System.out.println("Size of Original List: " + names.size());
// Create a HashSet from the list
Set<String> uniqueNamesSet = new HashSet<>(names);
System.out.println("Set created from List: " + uniqueNamesSet);
System.out.println("Size of Set: " + uniqueNamesSet.size());
// The difference in size tells us how many duplicates were removed
int duplicatesCount = names.size() - uniqueNamesSet.size();
System.out.println("Number of duplicates (excluding first occurrence): " + duplicatesCount);
}
}
以下是我们添加或修改的内容:
- 我们向
names列表中添加了另一个名字 "David",使列表稍微大一些。 System.out.println("Size of Original List: " + names.size());:我们使用size()方法打印原始列表的大小。Set<String> uniqueNamesSet = new HashSet<>(names);:这是一种直接从另一个Collection(如我们的ArrayList)创建HashSet的便捷方法。这样做时,HashSet会自动添加列表中的所有元素,并且由于它是Set,会丢弃任何重复元素。System.out.println("Size of Set: " + uniqueNamesSet.size());:我们打印HashSet的大小。这个大小代表唯一元素的数量。int duplicatesCount = names.size() - uniqueNamesSet.size();:我们计算列表大小和集合大小之间的差值。这个差值告诉我们有多少元素是重复的(不包括它们的首次出现)。
保存修改后的 DuplicateCheck.java 文件。
现在,在终端中再次编译程序:
javac DuplicateCheck.java
如果编译成功,运行程序:
java DuplicateCheck
你应该会看到类似以下的输出:
Original List: [Alice, Bob, Alice, Charlie, Bob, David]
Size of Original List: 6
Set created from List: [Alice, Bob, Charlie, David]
Size of Set: 4
Number of duplicates (excluding first occurrence): 2
注意,原始列表的大小是 6,但从中创建的 HashSet 的大小是 4。差值(6 - 4 = 2)正确地表明有两个重复的名字("Alice" 和 "Bob" 在首次出现后各又出现了一次)。
这展示了你可以多么轻松地使用 HashSet 来找出集合中唯一元素的数量或重复元素的数量。
使用空元素进行测试
在前面的步骤中,我们已经了解了 HashSet 如何处理非空的重复元素。现在,让我们来探究一下当尝试向 HashSet 中添加 null 元素时,它会有怎样的表现。了解集合如何处理 null 非常重要,因为如果处理不当,有时可能会导致意外的行为或错误。
HashSet 允许存在一个 null 元素。如果你多次尝试添加 null,只会存储第一个 null。
让我们再次修改 DuplicateCheck.java 程序来测试这一点。
在 WebIDE 代码编辑器中打开 DuplicateCheck.java 文件。
修改 main 方法,在列表中包含 null 值:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DuplicateCheck {
public static void main(String[] args) {
// Create a list with some duplicate and null elements
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add(null); // Add null
names.add("Alice"); // Duplicate
names.add("Charlie");
names.add(null); // Add null again
names.add("Bob"); // Duplicate
names.add("David");
names.add(null); // Add null a third time
System.out.println("Original List: " + names);
System.out.println("Size of Original List: " + names.size());
// Create a HashSet from the list
Set<String> uniqueNamesSet = new HashSet<>(names);
System.out.println("Set created from List: " + uniqueNamesSet);
System.out.println("Size of Set: " + uniqueNamesSet.size());
// The difference in size tells us how many duplicates were removed
// Note: This calculation is less straightforward with nulls and duplicates combined
// int duplicatesCount = names.size() - uniqueNamesSet.size();
// System.out.println("Number of duplicates (excluding first occurrence): " + duplicatesCount);
}
}
在这里,我们多次向 names 列表中添加了 null。我们还注释掉了重复元素计数的计算,因为当涉及 null 时,这个计算就变得不那么有意义了,而且我们主要关注的是集合对 null 的处理行为。
保存修改后的 DuplicateCheck.java 文件。
在终端中编译程序:
javac DuplicateCheck.java
如果编译成功,运行程序:
java DuplicateCheck
你应该会看到类似以下的输出:
Original List: [Alice, Bob, null, Alice, Charlie, null, Bob, David, null]
Size of Original List: 9
Set created from List: [null, Alice, Bob, Charlie, David]
Size of Set: 5
观察输出:
Original List显示了所有元素,包括多个null值。它的大小为 9。Set created from List只包含唯一元素。注意,即使null在列表中被多次添加,但在集合中它只出现了一次。集合的大小为 5(Alice、Bob、Charlie、David 和 null)。
这证实了 HashSet 允许存在一个 null 元素,并将后续添加的 null 视为重复元素,就像处理其他元素一样。
你现在已经成功测试了 HashSet 如何处理 null 元素。至此,我们对使用 HashSet 进行重复元素检查以及了解其对唯一元素和 null 元素的处理行为的探索就结束了。
总结
在本次实验中,我们学习了如何使用 HashSet 高效地检查 Java 集合中的重复元素。我们创建了一个包含重复元素的 List,然后遍历该列表,尝试将每个元素添加到 HashSet 中。通过检查 add() 方法的返回值(如果元素已存在则返回 false),我们能够识别出重复元素并将它们收集到另一个 HashSet 中。这种方法利用了 HashSet 的唯一元素特性和快速查找能力,从而实现了有效的重复元素检测。



