Java集合操作实战:从contains到iterator的完整指南
·
今天系统练习了Collection接口的核心方法,从contains判断到iterator遍历,每个方法都藏着一些容易忽略的细节。让我通过代码记录下这些重要发现。
1. contains方法:equals()的隐形调用
@Test
public void testContains() {
Collection coll = new ArrayList();
coll.add(new Person("李四", 18));
// 关键:contains会调用对象的equals()方法
boolean contains = coll.contains(new Person("李四", 18));
System.out.println("contains结果: " + contains); // true
// 前提:Person类必须正确重写equals()方法
// 否则比较的是对象地址,返回false
}
重要发现:contains()不是简单的==比较,它会自动调用元素的equals()方法。这意味着自定义类必须正确重写equals()和hashCode()。
2. containsAll:批量包含检查
@Test
public void testContainsAll() {
Collection coll = new ArrayList();
coll.add(666);
coll.add(888);
coll.add(true);
coll.add(new String("张三"));
// 检查另一个集合的所有元素是否都在当前集合中
Collection coll2 = Arrays.asList(true, new String("张三"));
boolean containsAll = coll.containsAll(coll2);
System.out.println("containsAll结果: " + containsAll); // true
// 注意:这也是基于equals()比较的
}
3. remove方法:不仅仅是删除
@Test
public void testRemove() {
Collection coll = new ArrayList();
coll.add(666);
coll.add(888);
coll.add(new String("张三"));
coll.add(new Person("李四", 18));
// 删除元素,同样依赖equals()
boolean removed = coll.remove(new String("张三"));
System.out.println("是否删除成功: " + removed); // true
System.out.println("删除后集合: " + coll);
// 如果元素不存在,remove()返回false
boolean notExist = coll.remove("不存在的元素");
System.out.println("删除不存在的元素: " + notExist); // false
}
4. removeAll vs retainAll:集合的差集与交集
@Test
public void testRemoveAllAndRetainAll() {
Collection coll = new ArrayList();
coll.add(666);
coll.add(888);
coll.add(true);
coll.add(new Person("李四", 18));
System.out.println("原始集合: " + coll);
// removeAll: 移除交集部分
Collection toRemove = Arrays.asList(666, new Person("李四", 18));
coll.removeAll(toRemove);
System.out.println("removeAll后: " + coll); // [888, true]
// retainAll: 保留交集部分
Collection toRetain = Arrays.asList(987, 666, true);
coll.retainAll(toRetain);
System.out.println("retainAll后: " + coll); // [true]
}
对比记忆:
removeAll():删掉两集合都有的元素(差集)retainAll():只保留两集合都有的元素(交集)
5. equals方法:顺序敏感的相等比较
@Test
public void testEquals() {
Collection coll1 = new ArrayList();
coll1.add(true);
coll1.add(888);
Collection coll2 = new ArrayList();
coll2.add(true);
coll2.add(888);
// 对于List,equals要求元素相同且顺序一致
System.out.println("顺序相同: " + coll1.equals(coll2)); // true
Collection coll3 = new ArrayList();
coll3.add(888);
coll3.add(true);
System.out.println("顺序不同: " + coll1.equals(coll3)); // false
// 注意:Set的equals不要求顺序一致
}
6. toArray与asList:集合与数组的转换
@Test
public void testArrayConversion() {
// 集合 -> 数组
Collection coll = Arrays.asList("A", "B", "C");
Object[] array = coll.toArray();
System.out.println("集合转数组: " + Arrays.toString(array));
// 数组 -> 集合(注意陷阱!)
System.out.println("\n--- 数组转集合的陷阱 ---");
// 基本类型数组:整个数组被视为一个元素
List<int[]> wrongList = Arrays.asList(new int[]{1, 2, 3});
System.out.println("int[]转List的大小: " + wrongList.size()); // 1
// 包装类型数组:每个元素被单独添加
List<Integer> rightList = Arrays.asList(new Integer[]{1, 2, 3});
System.out.println("Integer[]转List的大小: " + rightList.size()); // 3
// 注意:asList()返回的是固定大小的List,不能增删!
// rightList.add(4); // 会抛UnsupportedOperationException
}
关键提醒:Arrays.asList()对于基本类型数组和对象数组的行为不同!
7. hashCode方法:集合的哈希值计算
@Test
public void testHashCode() {
Collection coll1 = new ArrayList();
coll1.add(true);
coll1.add(888);
Collection coll2 = new ArrayList();
coll2.add(true);
coll2.add(888);
// 两个相等的集合,hashCode必须相等
System.out.println("coll1 hashCode: " + coll1.hashCode());
System.out.println("coll2 hashCode: " + coll2.hashCode());
System.out.println("hashCode是否相等: " +
(coll1.hashCode() == coll2.hashCode())); // true
}
8. iterator方法:集合遍历的正确姿势
@Test
public void testIterator() {
Collection<String> coll = new ArrayList<>();
coll.add("Java");
coll.add("Python");
coll.add("Go");
coll.add("JavaScript");
System.out.println("--- 使用iterator遍历 ---");
// 获取迭代器
Iterator<String> iterator = coll.iterator();
// 标准遍历方式
while (iterator.hasNext()) {
String language = iterator.next();
System.out.println("编程语言: " + language);
// 可以在遍历时安全删除
if ("Go".equals(language)) {
iterator.remove(); // 安全删除当前元素
System.out.println("已删除: Go");
}
}
System.out.println("\n--- 遍历后集合内容 ---");
System.out.println(coll); // [Java, Python, JavaScript]
System.out.println("\n--- 常见错误示例 ---");
// 错误1:重复调用next()跳过元素
Iterator<String> it1 = coll.iterator();
while (it1.hasNext()) {
System.out.println(it1.next()); // 正确
// System.out.println(it1.next()); // 错误!会跳过一个元素
}
// 错误2:遍历时用集合的remove()方法
Iterator<String> it2 = coll.iterator();
while (it2.hasNext()) {
String lang = it2.next();
if ("Java".equals(lang)) {
// coll.remove(lang); // 错误!会抛ConcurrentModificationException
it2.remove(); // 正确!使用迭代器的remove()
}
}
// 增强for循环底层也是iterator
System.out.println("\n--- 增强for循环 ---");
for (String lang : coll) {
System.out.println("语言: " + lang);
// 这里也不能直接调用coll.remove()
}
}
今日学习总结
核心收获:
-
equals()是集合操作的基石
- contains、remove、containsAll等都依赖equals()
- 自定义类必须正确重写equals()和hashCode()
-
集合运算的三种模式
- 单个操作:add、remove、contains
- 批量操作:addAll、removeAll、retainAll、containsAll
- 转换操作:toArray、asList
-
数组与集合转换的陷阱
- 基本类型数组用asList()会得到单个元素
- asList()返回的是固定大小的List
-
迭代器的正确使用
- 遍历时删除必须用iterator.remove()
- 不能混用集合的remove()方法
- 每个迭代器只能使用一次
实际应用建议:
// 1. 判断元素是否存在
if (collection.contains(target)) {
// 确保元素类重写了equals()
}
// 2. 批量删除
collection.removeAll(toRemove); // 比循环删除高效
// 3. 安全遍历删除
Iterator<T> it = collection.iterator();
while (it.hasNext()) {
T item = it.next();
if (shouldRemove(item)) {
it.remove(); // 唯一安全的方式
}
}
// 4. 集合比较
if (list1.equals(list2)) {
// List要求顺序一致
}
if (set1.equals(set2)) {
// Set不要求顺序一致
}
性能注意事项:
contains()在ArrayList中是O(n),在HashSet中是O(1)- 频繁的contains检查考虑使用Set
- 大集合的遍历考虑使用Iterator而非get(index)
练习感悟:集合的API设计体现了Java的面向对象思想。每个方法都不是孤立的,而是通过equals()、hashCode()等机制相互关联。理解这些内在联系,才能真正掌握集合框架的精髓。
更多推荐




所有评论(0)