哈喽,大家好!我是小米,一个热爱分享技术的大哥哥,今天要和大家聊聊我们日常写代码绕不开的一个话题——如何遍历一个 List。虽然这是基础中的基础,但正因为它常见,咱们更要把这个基础打牢,毕竟“地基稳了,房子才能盖得高”嘛。
小伙伴们平时在写代码时,可能最常用的就是 for 循环或者增强 for 循环来遍历 List,对吧?可你有没有想过,Java 中遍历 List 的方式有几种?它们的实现原理是什么?哪种方式在特定场景下表现更好?别急,今天我们就通过几个小故事,把这个问题彻底说清楚。
遍历方式一:经典的 for 循环
小故事:忙碌的快递员
想象一下,我们的 List 是一排快递箱,而我们需要逐一检查这些快递。用 for 循环就像雇了一个快递员,按照箱子的编号(索引)一个个检查。
代码实现:
实现原理
for 循环通过索引访问每一个元素,list.get(i) 会调用 List 接口实现的 get() 方法。对于 ArrayList,这个方法是 O(1) 的,因为它直接访问底层数组。而对于 LinkedList,则是 O(n) 的,因为它需要从头开始遍历链表找到对应的元素。
优缺点
- 优点:灵活,可以访问索引。
- 缺点:如果使用的是 LinkedList,性能可能不佳。
遍历方式二:增强 for 循环(for-each)
小故事:机器人搬运工
快递员太累了,我们换成了机器人。机器人不关心快递的编号,只要把每个箱子搬出来即可。
代码实现:
实现原理
增强 for 循环底层依赖的是 Iterator。当你写下 for (String item : list) 时,Java 编译器会将它转换为一个 Iterator 对象并调用其 hasNext() 和 next() 方法。
例如,编译后大致相当于:
优缺点
- 优点:代码简洁,适合遍历所有元素。
- 缺点:无法访问索引,不能灵活修改 List。
遍历方式三:Iterator 和 ListIterator
小故事:双向传送带
有些场景下,机器人需要走到某个快递箱时突然回头,比如需要倒着检查快递的标签。这时候,就需要一种更灵活的工具——Iterator 和 ListIterator。
代码实现:
实现原理
- Iterator:通过 hasNext() 和 next() 依次获取元素,它是单向的。
- ListIterator:是 Iterator 的增强版,支持双向遍历,提供了 hasPrevious() 和 previous() 方法。
优缺点
- 优点:Iterator 提供了 fail-fast 机制,能在集合结构被修改时及时抛出 ConcurrentModificationException。
- 缺点:操作较繁琐,尤其是需要双向遍历时。
遍历方式四:Stream API
小故事:流水线工厂
时代进步了,我们用上了自动化流水线。快递箱在流水线上一个个通过,系统自动处理。
代码实现:
实现原理
Stream 是 Java 8 引入的一个功能,它并没有改变 List 本身,而是提供了一种对集合操作的声明式方式。stream() 会生成一个 Stream 对象,forEach() 方法对每个元素应用给定的操作。
优缺点
- 优点:代码优雅,支持并行流处理,适合大数据量操作。
- 缺点:在简单场景下可能显得“杀鸡用牛刀”。
遍历方式五:forEach 方法
小故事:语音助手登场
如果想让快递员听命于语音助手,直接告诉他“依次打开每个箱子”,那么就可以使用 List 自带的 forEach 方法。
代码实现:
实现原理
forEach 是 Java 8 中添加到 Iterable 接口的默认方法。底层原理与增强 for 循环类似,但代码更加简洁。
优缺点
- 优点:语法简洁,直观易懂。
- 缺点:和增强 for 循环一样,不支持访问索引。
哪种方式最优?最佳实践来啦!
性能分析
- 如果需要频繁访问索引(比如访问特定元素或跳过某些元素),优先使用经典的 for 循环。
- 如果不关心索引,增强 for 循环和 forEach 方法更适合,代码简洁。
- 在需要操作大量数据或并行处理时,Stream API 是最佳选择。
- 对于双向遍历,非 ListIterator 莫属。
小米的建议
- 优雅为主,性能为辅:在大多数业务场景中,性能差异可以忽略,优先选择简洁且可读性高的方式。
- 避免 LinkedList 坑:如果你不知道具体的 List 类型,尽量少用经典的 for 循环。
- 注意 fail-fast:如果遍历时需要修改 List,请使用 Iterator,避免出现意料之外的 ConcurrentModificationException。
END
从经典的 for 循环到现代化的 Stream API,Java 提供了多种遍历方式,每种方式各有优劣。选择哪种方式不仅取决于你习惯写哪种代码,还取决于业务场景的具体需求。
小伙伴们,如果你觉得今天的文章有帮助,不妨点个赞或者转发一下,让更多人看到!你平时最常用哪种方式遍历 List?有没有遇到过哪些奇葩的坑?评论区一起聊聊吧~
我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!