本文主要梳理 Java 集合框架常见的遍历/迭代方式,如下:
- 1、List 的遍历方式
- 1、for 循环
- 2、增强的 for 循环
- 3、Iterator 迭代器
- 4、ListIterator 双向迭代器
- 5、Iterable.forEach + Lambda
- 6、Stream.forEach
- 2、Set 的遍历方式
- 1、增强的 for 循环
- 2、Iterator 迭代器
- 3、Iterable.forEach + Lambda
- 4、Stream.forEach
- 3、Map 的遍历方式
- 1、Map.Entry + foreach 的迭代方式
- 2、Map.Entry + Iterator 的迭代方式
- 3、keySet + foreach 的迭代方式
- 4、keySet + Iterator 的迭代方式
- 5、Iterable.forEach + Lambda
- 6、Stream.forEach
- 4、总结
- 5、参考
1、List 的遍历方式
List 的遍历主要有以下几种方式:
- 1、for 循环
- 2、增强的 for 循环
- 3、Iterator 迭代器
- 4、ListIterator 双向迭代器
- 5、Iterable.forEach + Lambda
- 6、Stream.forEach
其中 2、3、5 本质上可以说是一样的使用 Iterator 迭代器。而 ListIterator 则是 Iterator 的一个变种(双向迭代, 可以进行 add、remove、set、定位当前索引),使用如下:
public static void main(String[] args) { List<String> strList = new ArrayList<>(); /// List<String> strList = new LinkedList<>(); strList.add("1st"); strList.add("2nd"); strList.add("3rd"); strList.add("4th"); // 1、 索引下标 for 循环 // 注意:对于链表形式的实现,每次都是 O(N),总的是(O(N*N)),效率较低 System.out.println("for 循环"); for (int i = 0, length = strList.size(); i < length; i++) { System.out.println(strList.get(i)); } // 2、 增强的 for 循环,内部是迭代器实现 // https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2 System.out.println("增强的 for 循环"); for (String str : strList) { System.out.println(str); } // 3.1、 Iterator 迭代器 while 形式 System.out.println("Iterator 迭代器 while 形式"); Iterator<String> itr = strList.iterator(); while (itr.hasNext()) { String string = itr.next(); System.out.println(string); } // 3.2、 Iterator 迭代器 for 形式 System.out.println("Iterator 迭代器 for 形式"); for (Iterator<String> iterator = strList.iterator(); iterator.hasNext();) { String string = iterator.next(); System.out.println(string); } // 4、 ListIterator 双向迭代器, Iterator 的子类型, List 集合特有的方式 // ListIterator 双向, 还可以进行 add、remove、set、定位当前索引 // ArrayList 和 LinkedList 各自的内部类实现 ListIterator<String> listItr = strList.listIterator(); System.out.println("ListIterator 反向迭代1"); // 这里并没有上一个,所以没有 while (listItr.hasPrevious()) { String string = listItr.previous(); System.out.println(string); } System.out.println("ListIterator 正向迭代"); while (listItr.hasNext()) { String string = listItr.next(); System.out.println(string); } System.out.println("ListIterator 反向迭代2"); while (listItr.hasPrevious()) { String string = listItr.previous(); System.out.println(string); } // 5、 Java 8 Lambda 迭代方式 // 本质上还是增强的 for 循环(内部是迭代器实现),将对应的操作封装到 Consumer 里面 System.out.println("Java 8 Lambda 迭代方式"); strList.forEach(str -> System.out.println(str)); System.out.println("=-="); strList.forEach(System.out::println); strList.forEach(str -> { System.out.println("---"); System.out.println(str); }); // 比较完整的写法,其实就是自定义 Consumer 接口的实现类,重写 accept 方法 strList.forEach(new Consumer<String>() { @Override public void accept(String str) { System.out.println("-=-"); System.out.println(str); }; }); // 6、 Java 8 Stream 迭代方式 System.out.println("Java 8 Stream 迭代方式"); strList.stream().forEach(System.out::println); System.out.println("-~-"); strList.stream().forEach(str -> System.out.println(str)); strList.stream().forEach(str -> { System.out.println("==="); System.out.println(str); }); // 也可以使用自定义 Consumer 接口的实现类的方式 }
注:因 LinkedList 内部为双向链表实现,通过 LinkedList.get(index) 获取元素每次都是 O(N) ,效率相对较低,建议使用 Iterator 的方式(增强的 for 循环或者直接使用 Iterator)。
参考:Ways to iterate over a list in Java:https://stackoverflow.com/questions/18410035/ways-to-iterate-over-a-list-in-java
2、Set 的遍历方式
对比 List 可知,Set 没有 get(index) 的方式,也没有 ListIterator 双向迭代器 ,其他的都是类似的,Set 的遍历主要有以下几种方式:
- 1、增强的 for 循环
- 2、Iterator 迭代器
- 3、Iterable.forEach + Lambda
- 4、Stream.forEach
使用代码如下:
public static void main(String[] args) { Set<String> strSet = new HashSet<>(); // Set<String> strSet = new LinkedHashSet<>(); // Set<String> strSet = new TreeSet<>(); strSet.add("1st"); strSet.add("2nd"); strSet.add("3rd"); strSet.add("4th"); // 1、 增强的 for 循环 System.out.println("增强的 for 循环"); for (String str : strSet) { System.out.println(str); } // 2.1、 Iterator 迭代器 while 形式 System.out.println("Iterator 迭代器 while 形式"); Iterator<String> itr = strSet.iterator(); while (itr.hasNext()) { String string = itr.next(); System.out.println(string); } // 2.2、 Iterator 迭代器 for 形式 System.out.println("Iterator 迭代器 for 形式"); for (Iterator<String> iterator = strSet.iterator(); iterator.hasNext();) { String string = iterator.next(); System.out.println(string); } // 3、 Java 8 Lambda 迭代方式 // 本质上还是增强的 for 循环(内部是迭代器实现),将对应的操作封装到 Consumer 里面 System.out.println("Java 8 Lambda 迭代方式"); strSet.forEach(str -> System.out.println(str)); // 4、 Java 8 Stream 迭代方式 System.out.println("Java 8 Stream 迭代方式"); strSet.stream().forEach(System.out::println); System.out.println("-~-"); strSet.stream().forEach(str -> System.out.println(str)); }
另外还有一些方式是先转成 Array 再遍历。。。
参考:How to Iterate over a Set/HashSet without an Iterator?:https://stackoverflow.com/questions/12455737/how-to-iterate-over-a-set-hashset-without-an-iterator
3、Map 的遍历方式
Map 比较特殊,它是 k-v 对,遍历也会相对不一样。这里总结几种遍历方式:
- 1、Map.Entry + foreach 的迭代方式
- 2、Map.Entry + Iterator 的迭代方式
- 3、keySet + foreach 的迭代方式
- 4、keySet + Iterator 的迭代方式
- 5、Iterable.forEach + Lambda
- 6、Stream.forEach
使用如下:
public static void main(String[] args) { Map<String, String> strMap = new HashMap<>(); // Map<String, String> strMap = new LinkedHashMap<>(); // Map<String, String> strMap = new TreeMap<>(); strMap.put("1", "1st"); strMap.put("2", "2nd"); strMap.put("3", "3rd"); strMap.put("4", "4th"); // 1、 Map.Entry + foreach 的迭代方式 System.out.println("Map.Entry + foreach 迭代方式"); for (Map.Entry<String, String> entry : strMap.entrySet()) { System.out.println(entry.getKey() + "=" + entry.getValue()); } // 2.1、 Map.Entry + Iterator 的 while 迭代方式 System.out.println("Map.Entry + Iterator 的 while 迭代方式"); Iterator<Map.Entry<String, String>> mapItr = strMap.entrySet().iterator(); while (mapItr.hasNext()) { Map.Entry<String, String> entry = mapItr.next(); System.out.println(entry.getKey() + "=" + entry.getValue()); } // 2.2、 Map.Entry + Iterator 的 for 迭代方式 System.out.println("Map.Entry + Iterator 的 for 迭代方式"); for (Iterator<Map.Entry<String, String>> mapItrs = strMap.entrySet().iterator(); mapItrs.hasNext();) { Map.Entry<String, String> entry = mapItrs.next(); System.out.println(entry.getKey() + "=" + entry.getValue()); } // 3、 keySet + foreach 的迭代方式 System.out.println("keySet + foreach 的迭代方式"); Set<String> keySet = strMap.keySet(); for (String key : keySet) { System.out.println(key + "=" + strMap.get(key)); } // 4、 keySet + Iterator 的迭代方式 System.out.println("keySet + Iterator 的迭代方式"); Iterator<String> strItr = strMap.keySet().iterator(); while (strItr.hasNext()) { String key = strItr.next(); System.out.println(key + "=" + strMap.get(key)); } // 以下这些都可以通过自定义 Consumer 接口的实现类来处理 // 5、 Iterable.forEach + Lambda (Java 8 Lambda 迭代方式) System.out.println("Iterable.forEach + Lambda (Java 8 Lambda 迭代方式)"); strMap.forEach((k, v) -> System.out.println(k + "=" + v)); // 6、 Stream.forEach ( Java 8 Stream 迭代方式) System.out.println("Stream.forEach ( Java 8 Stream 迭代方式)"); strMap.entrySet().forEach((entry) -> System.out.println(entry.getKey() + "=" + entry.getValue())); }
4、总结
总的来说,基本上就是 : 索引 + 增强的 foreach + Iterator + Iterable.forEach + Stream.forEach
5、参考
- 相关测试代码 github 链接:https://github.com/wpbxin/java-learning-station 的 java-collections-framework-learning 模块
- The enhanced for statement:https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2
- Ways to iterate over a list in Java:https://stackoverflow.com/questions/18410035/ways-to-iterate-over-a-list-in-java
- How does the Java 'for each' loop work?:https://stackoverflow.com/questions/85190/how-does-the-java-for-each-loop-work
- How to Iterate over a Set/HashSet without an Iterator?:https://stackoverflow.com/questions/12455737/how-to-iterate-over-a-set-hashset-without-an-iterator
- How do I efficiently iterate over each entry in a Java Map?:https://stackoverflow.com/questions/46898/how-do-i-efficiently-iterate-over-each-entry-in-a-java-map
- How to for each the hashmap? [duplicate]:https://stackoverflow.com/questions/4234985/how-to-for-each-the-hashmap
- HowToDoInJava : Java 8 forEach():https://howtodoinjava.com/java8/foreach-method-example/