本文主要梳理 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/