Java集合遍历案例怎么编写

wen java案例 26

Java集合遍历案例怎么编写:从基础到高级的完整指南

目录导读

  • Java集合遍历的五大经典方式

    Java集合遍历案例怎么编写

  • 各遍历方式的代码案例与性能对比

  • 遍历过程中如何安全删除元素

  • 常见遍历错误与最佳实践

  • 问答环节:面试高频问题解析


Java集合遍历的五大经典方式

在Java开发中,集合遍历是日常编码中最高频的操作之一,根据不同的JDK版本和场景需求,常见的遍历方式包括:

  • 传统for循环:适用于List(如ArrayList、LinkedList)
  • 增强for循环(for-each):兼容所有Collection接口实现
  • 迭代器(Iterator):支持遍历时的安全删除操作
  • Java 8 Stream API:支持函数式编程与链式操作
  • ListIterator:支持双向遍历(仅适用于List)

理解这些方式的适用场景,能帮助你在编写代码时兼顾性能与可读性。

各遍历方式的代码案例与性能对比

ArrayList遍历(推荐使用for-each或Stream)

List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("Go");
// 方式1:增强for
for (String s : list) {
    System.out.println(s);
}
// 方式2:Stream API(Java 8+)
list.stream().forEach(System.out::println);
// 方式3:传统for(性能最优,但代码略长)
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

性能对比:在ArrayList上,传统for循环通过索引直接访问,速度最快;增强for循环和Stream API性能相近,但在大数据集上Stream会有额外开销。

HashSet遍历(只能用迭代器或增强for)

Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
// 方式1:迭代器
Iterator<Integer> it = set.iterator();
while (it.hasNext()) {
    System.out.println(it.next());
}
// 方式2:for-each(本质也是迭代器)
for (Integer num : set) {
    System.out.println(num);
}

HashMap遍历(四种方法)

Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
// 方法1:遍历EntrySet(推荐,效率最高)
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println(entry.getKey() + ":" + entry.getValue());
}
// 方法2:遍历KeySet然后取值(低效,需二次查询)
for (String key : map.keySet()) {
    System.out.println(key + ":" + map.get(key));
}
// 方法3:Java 8 forEach
map.forEach((k, v) -> System.out.println(k + ":" + v));
// 方法4:迭代器遍历EntrySet
Iterator<Map.Entry<String, Integer>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
    Map.Entry<String, Integer> entry = iter.next();
    System.out.println(entry.getKey() + ":" + entry.getValue());
}

关键点:遍历HashMap时优先使用entrySet(),因为keySet()每次get()都会额外计算哈希值,在百万级数据时性能差异显著。

遍历过程中如何安全删除元素

这是Java集合面试中最高频的陷阱之一。直接在for-each循环中调用list.remove()会抛出ConcurrentModificationException

错误示范:

List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
for (String s : list) {
    if (s.equals("b")) {
        list.remove(s); // 抛出异常!
    }
}

正确做法:

// 方法1:使用迭代器移除
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String s = it.next();
    if (s.equals("b")) {
        it.remove(); // 安全,因为迭代器维护了modCount一致性
    }
}
// 方法2:使用removeIf(Java 8+,推荐)
list.removeIf(s -> s.equals("b"));
// 方法3:收集需要删除的元素,遍历结束后统一删除
List<String> toRemove = new ArrayList<>();
for (String s : list) {
    if (s.equals("b")) toRemove.add(s);
}
list.removeAll(toRemove);

特别注意:如果使用CopyOnWriteArrayList,可以在for-each中直接删除,但会增加内存复制开销。

常见遍历错误与最佳实践

错误1:在遍历中修改集合结构(增加元素)

// 会导致ConcurrentModificationException
for (String s : list) {
    if (s.equals("a")) list.add("new");
}

解决:使用ListIterator的add()方法。

ListIterator<String> listIt = list.listIterator();
while (listIt.hasNext()) {
    String s = listIt.next();
    if (s.equals("a")) {
        listIt.add("new"); // 在当前位置后插入
    }
}

错误2:忽略空指针检查

// 如果collection为null,for-each会直接抛NPE
Collection<String> col = getCollection(); // 可能为null
if (col != null) {
    for (String s : col) {...}
}
  • 单线程:for-each 或 Stream(代码简洁)
  • 需要删除:Iterator.remove() 或 removeIf()
  • 需要下标:传统for循环(如更新指定位置元素)
  • 高并发:使用并发集合如ConcurrentHashMap,其迭代器是弱一致性的

问答环节:面试高频问题解析

Q1: 为什么for-each遍历时不能添加或删除元素? A: for-each底层依赖Iterator,但内部没有暴露remove方法,当集合的modCount(修改次数)与迭代器记录的expectedModCount不一致时,会触发fast-fail机制,抛出ConcurrentModificationException,而Iterator.remove()会同步更新expectedModCount。

Q2: ArrayList和LinkedList的遍历性能差异有多大? A: ArrayList通过索引随机访问时间复杂度为O(1),传统for循环最快,LinkedList基于双向链表,get(i)需要遍历链表到索引位置(O(n)),因此LinkedList绝对不要用传统for循环! 应使用迭代器或for-each,它们使用指针遍历(O(n))。

Q3: Stream遍历会改变原始集合吗? A: 不会,Stream的forEach操作是只读的,如果需要修改集合元素,建议在forEach外部收集结果并使用collect()。

Q4: 遍历HashMap时,EntrySet和KeySet哪个更快? A: EntrySet更快,KeySet遍历时每次get(key)都需要调用hashCode()和equals(),而EntrySet直接获取键值对对象,在数据量超过100万条时,性能差距可达数倍。

Q5: 如何安全地在多线程环境下遍历集合? A: 1)使用java.util.concurrent包下的集合,如CopyOnWriteArrayList、ConcurrentHashMap;2)使用同步包装器Collections.synchronizedList(new ArrayList<>()),但需配合synchronized块进行迭代;3)使用显式锁(Lock)保证遍历与修改互斥。


通过以上案例和原理分析,你对“Java集合遍历案例怎么编写”应该有了系统性的认识,实际操作时,请根据集合类型、修改需求和性能要求,选择最合适的遍历方式,并严格遵守安全删除的规范。用对遍历方式,代码既能跑得快,又能跑得稳

抱歉,评论功能暂时关闭!