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

 

posted @ 2020-09-21 17:04  心明谭  阅读(2592)  评论(0编辑  收藏  举报