Java8集合框架——集合的遍歷(迭代)


  本文主要梳理 Java 集合框架常見的遍歷/迭代方式,如下:

 

1、List 的遍歷方式

  List 的遍歷主要有以下幾種方式:

  其中 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 的遍歷主要有以下幾種方式:

  使用代碼如下:

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、參考

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM