• Stream 流式编程 ( Java 8新特性 )


    Stream 流式计算

    什么是 Stream 流式计算?
    • Stream 流式计算是在jdk 1.8后引入的新特性,将集合或数组 转换成一种流的元素序列。流不是集合中的元素,也不是一种数据结构,不负责数据的存储。Stream 流也不会改变源对象(源集合)

    • Stream 接口中几乎所有方法的参数都是四大函数式接口接口类型的参数。而函数式接口可以使用 lambda 表达式来简化开发,并且 Stream 接口中的方法基本都是返回对象本身(返回对象本身的方法可以使用链式编程)。所以在使用 Stream 流式计算时,基本上都用到了函数式接口、lambda表达式 和 链式编程。


    集合转换成
    • Collection接口在 jdk 1.8 后新增了一个 stream() 方法,调用该方法会得到一个 Stream 流对象。通过这个对象可以调用 Stream 接口相应的方法对集合进行过滤排序截断(丢弃)截断(获取)转换遍历计数拼接取最大值取最小值 等操作。

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(12, 25, 4, 17, 3);
          // 将集合转换成流
          Stream<Integer> stream = list.stream();
          // 对流进行计算操作:遍历Stream流,将大于10的元素中,截取前面2个输出
          stream.filter((i)->{return i > 10;}).limit(2).forEach(System.out::println);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    数组转换成
    • Stream 接口也提供了一个 of() 方法,底层基于Arrays.stream() 来将数组转换成流。通过流对象可以调用 Stream 接口相应的方法对集合进行过滤排序截断(丢弃)截断(获取)转换遍历计数拼接取最大值取最小值 等操作。

      public static void main(String[] args) {
          Integer[] array = {12, 25, 4, 17, 3};
          // 将数组转换成流
          Stream<Integer> stream = Stream.of(array);
          // 对流进行计算操作:遍历Stream流,将大于10的元素中,截取前面2个输出
          stream.filter((i)->{return i > 10;}).limit(2).forEach(System.out::println);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    Stream 流式计算的步骤:
    • 创建 Stream 流对象。
    • 对流中元素序列进行处理。
    • 执行中间操作链,产生结果。

    img


    集合获取 Stream 流
    • Collection 集合获取 Stream 流 (通过 Collection 集合的 stream() 方法来获取)

      // List集合获取 Stream 流
      ArrayList<Integer> list = new ArrayList<>();
      Stream<Integer> stream = list.stream();
      // 通过 Stream 流对象操作数据  (代码省略 . . .)
      
      
      // List集合获取 Stream 流
      List<Integer> list = Arrays.asList(4, 3, 5, 7, 2);
      Stream<Integer> stream = list.stream();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      // Set集合获取 Stream 流
      HashSet<String> set = new HashSet<>();
      Stream<String> stream = set.stream();
      // 通过 Stream 流对象操作数据  (代码省略 . . .)
      
      • 1
      • 2
      • 3
      • 4

    数组获取 Stream 流
    • 数组获取 Stream 流 (通过 Stream 的 of() 方法来获取,of() 方法的底层通过 工具类Arraysstream()方法来获取)

      // 数组获取 Stream 流
      Integer[] arr = {4, 3, 5, 7, 2};
      Stream<Integer> stream = Stream.of(arr);
      // 通过 Stream 流对象操作数据  (代码省略 . . .)
      
      
       // 数组获取 Stream 流
      Stream<Integer> stream = Stream.of(4, 3, 5, 7, 2);
      // 通过 Stream 流对象操作数据  (代码省略 . . .)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

    Stream 流转换成集合
    • Stream 流转换成 List 集合(通过 Stream 接口的 collect() 方法来转换)

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(14, 3, 5, 7, 12);
          // List集合获取 Stream 流
          Stream<Integer> stream = list.stream();
          // 操作 Stream 流
          List<Integer> collect = stream
                                  	// 获取 > 5 的元素
                                  	.filter((i) -> { return i > 5; })
                                  	// 对元素进行升序排序
                                  	.sorted()
                                  	// 将 Stream 流转换成 List 集合
                                  	.collect(Collectors.toList());
          // 遍历 转换后的 List 集合
          for (Integer i : collect) {
              System.out.println(i);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    • Stream 流转换成 Set 集合(通过 Stream 接口的 collect() 方法来转换)

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(14, 3, 5, 7, 12);
          // List集合获取 Stream 流
          Stream<Integer> stream = list.stream();
          // 操作 Stream 流
          Set<Integer> collect = stream
                                  	// 获取 > 5 的元素
                                  	.filter((i) -> { return i > 5; })
                                  	// 对元素进行升序排序
                                  	.sorted()
                                  	// 将 Stream 流转换成 Set 集合
                                  	.collect(Collectors.toSet());
          // 遍历 转换后的 Set 集合
          for (Integer i : collect) {
              System.out.println(i);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

    Stream 流转换成数组
    • Stream 流转换成数组(通过 Stream 接口的 toArray() 方法来转换)

      public static void main(String[] args) {
          // 数组获取 Stream 流
          Stream<Integer> stream = Stream.of(14, 3, 5, 7, 12);
          // 操作 Stream 流
          Integer[] array = stream
                              // 获取 > 5 的元素
                              .filter((i) -> { return i > 5; })
                              // 对元素进行升序排序
                              .sorted()
                              // 将 Stream 流转换成 数组
                              .toArray(Integer[]::new);
          // 遍历 转换后的 数组
          for (Integer i : array) {
              System.out.println(i);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

    Stream 接口常用API
    • Stream of(T… values) 数组获取 Stream 流

      public static void main(String[] args) {
          // 数组获取 Stream 流
          Stream<Integer> stream = Stream.of(14, 3, 5, 7, 12);
      }
      
      • 1
      • 2
      • 3
      • 4

    • Stream filter(Predicate predicate) 过滤

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(12, 25, 4, 17, 3);
          
          // 获取 Stream 流对象进行操作
          list.stream()
              // 过滤(获取大于10的元素)
              .filter((i) -> {return i > 10;})
              // 遍历
              .forEach(System.out::println);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    • Stream sorted(Comparator comparator) 排序

      @Data
      @NoArgsConstructor
      @AllArgsConstructor
      class User {
          private int id;
          private String name;
          private int age;
      }
      
      
      public class Test {
      
          public static void main(String[] args) {
              ArrayList<User> list = new ArrayList<>();
              list.add(new User(1, "王一", 27));
              list.add(new User(2, "王二", 23));
              list.add(new User(3, "王三", 25));
              list.add(new User(4, "王四", 24));
      
              // 获取 Stream 流对象进行操作
              list.stream()
                      // 根据年龄排序
                      .sorted(Comparator.comparing(User::getAge))   // 升序排序
                  	//等价于: .sorted(Comparator.comparing((user)->{return user.getAge();}))
                      .sorted(Comparator.comparing(User::getAge).reversed())  // 降序排序
                      // 遍历
                      .forEach(System.out::println);
              
              // 获取 Stream 流对象进行操作
              list.stream()
                      // 根据年龄排序
                      .sorted((c1, c2) -> c1.getAge().compareTo(c2.getAge()))  // 升序排序
                      .sorted((c1, c2) -> c2.getAge().compareTo(c1.getAge()))  // 降序排序
                      .forEach(System.out::println);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36

      升序排序

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(5, 3, 7, 9, 4);
          
          // 获取集合的 Stream 流对象
          list.stream()
              // 升序排序
              .sorted()
              // 遍历
              .forEach(System.out::println);
          
          
          // 获取集合的 Stream 流对象
          list.stream()
              // 升序排序
              .sorted((c1, c2) -> c1.compareTo(c2))
              // 遍历
              .forEach(System.out::println);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19

      降序排序

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(5, 3, 7, 9, 4);
          
          // 获取集合的 Stream 流对象
          list.stream()
              // 降序排序(升序排序的反向排序)
              .sorted(Comparator.reverseOrder())
              // 遍历
              .forEach(System.out::println);
          
          
          
          // 获取集合的 Stream 流对象
          list.stream()
              // 降序排序
              .sorted((c1, c2) -> c2.compareTo(c1)) 
              // 遍历
              .forEach(System.out::println);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

      多字段排序 (使用Comparator比较器的comparing() 和 thenComparing() 来实现)

      @Data
      @NoArgsConstructor
      @AllArgsConstructor
      class User {
          private int id;
          private String name;
          private int age;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      public class Test {
      
          public static void main(String[] args) {
              ArrayList<User> list = new ArrayList<>();
              list.add(new User(1, "王一", 27));
              list.add(new User(2, "王二", 23));
              list.add(new User(3, "王三", 27));
              list.add(new User(4, "王四", 24));
      
              // 获取 Stream 流对象进行操作
              list.stream()
                      // 升序排序(先根据年龄排序,如果年龄相同,则年龄相同的用户根据 id 排序)
                      .sorted(Comparator.comparing(User::getAge).thenComparing(User::getId))
                      // 遍历
                      .forEach(System.out::println);
              
              
              // 获取 Stream 流对象进行操作
              list.stream()
                      // 降序排序(先根据年龄排序,如果年龄相同,则年龄相同的用户根据 id 排序)
                      .sorted(Comparator.comparing(User::getAge).thenComparing(User::getId).reversed())
                      // 遍历
                      .forEach(System.out::println);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25

      多字段即升序 又 降序排序 (使用Stream的sorted()方法,Comparator比较器的comparing() 和 thenComparing() 作为参数)

      @Data
      @NoArgsConstructor
      @AllArgsConstructor
      class User {
          private int id;
          private String name;
          private int age;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      public class Test {
      
          public static void main(String[] args) {
              ArrayList<User> list = new ArrayList<>();
              list.add(new User(1, "王一", 27));
              list.add(new User(2, "王二", 23));
              list.add(new User(3, "王三", 27));
              list.add(new User(4, "王四", 24));
      
              // 获取 Stream 流对象进行操作
              list.stream()
                      // 即升序又降序排序(先根据年龄升序排序,如果年龄相同,则年龄相同的用户根据 id 降序排序)
                      .sorted(Comparator.comparing(User::getAge).thenComparing(User::getId , Comparator.reverseOrder()))
                      // 遍历
                      .forEach(System.out::println);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17

    • Stream limit(long maxSize) 截取(截取前面n个元素)

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(5, 3, 7, 9, 4);
      
          // 获取集合的 Stream 流对象
          list.stream()
              // 截取(截取前面前4个元素)
              .limit(4)
              // 遍历
              .forEach(System.out::println);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    • Stream skip(long n) 丢弃(丢弃前面n个元素)

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(5, 3, 7, 9, 4);
      
          // 获取集合的 Stream 流对象
          list.stream()
              // 丢弃(丢弃前面4个元素)
              .skip(4)
              // 遍历
              .forEach(System.out::println);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    • Stream map(Function mapper) 转换(将 一个 Stream 流 转换成 另一个 Stream 流)

      转换流中元素的类型

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(5, 3, 7, 9, 4);
      
          // 将 Stream 流的 Integer类型 转换成 String类型
          Stream<String> stream = list.stream().map(item -> item.toString());
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      对 流 中元素进行运算处理

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(5, 3, 7, 9, 4);
      
          // 将 Stream 流中元素左移两位,即乘以四
          List<Integer> collect = list.stream().map(item -> item << 2).collect(Collectors.toList());
          System.out.println(collect.toString());
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      对 流 中元素进行大小写转换

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<String> list = Arrays.asList("a", "b", "c", "d", "e");
      
          // 将 Stream 流中全部元素转换成 大写字母
          Stream<String> stream = list.stream().map(item -> item.toUpperCase());
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    • Stream flatMap(Function> mapper)

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<String> list = Arrays.asList("hello", "word");
          System.out.println(list.toString());
      
          List<String> collect = list.stream()
              						// 将若干个子管道中的数据,全都展开到父管道中进行处理
              						.flatMap(item -> Arrays.stream(item.split(""))) // [h,e,l,l,o,w,o,r,l,d]
              						.collect(Collectors.toList());
          System.out.println(collect);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    • void forEach(Consumer action) 遍历(逐个处理流元素)

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(5, 3, 7, 9, 4);
      
          // 获取集合的 Stream 流对象
          list.stream()
              // 遍历
              .forEach(System.out::println);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

    • long count() 计数(返回流中元素个数)

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(5, 3, 7, 9, 4);
          // 获取集合的 Stream 流中元素个数
          long count = list.stream().count();
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

    • Stream concat(Stream a, Stream b) 拼接(对两个流对象进行拼接)

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list_01 = Arrays.asList(1, 2, 3, 4, 5);
          List<Integer> list_02 = Arrays.asList(6, 7, 8, 9, 0);
          // 将两个 Stream 流拼接(首尾合并),成一个新的 Stream 流
          Stream<Integer> stream = Stream.concat(list_01.stream(), list_02.stream());
          stream.forEach(System.out::println);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    • Optional max(Comparator comparator) 根据Comparator比较器获取最大的元素

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(5, 3, 7, 9, 4);
          // 获取序列中的值最大的元素
          Optional<Integer> max = list.stream().max(Comparator.comparing((integer -> integer)));
          System.out.println(max.get());
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    • Optional min(Comparator comparator) flatMap 根据Comparator比较器获取最小的元素

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(5, 3, 7, 9, 4);
          // 获取序列中的值最小的元素
          Optional<Integer> max = list.stream().min(Comparator.comparing((integer -> integer)));
          System.out.println(max.get());
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    • Stream distinct() 对 Stream 流中所有元素进行去重,返回新的 Stream 流

      public static void main(String[] args) {
          // 将数组变成一个列表集合
          List<Integer> list = Arrays.asList(5, 3, 7, 5, 4);
      
          // 获取集合的 Stream 流对象
          list.stream()
              // 相同元素去重
              .distinct()
              // 遍历
              .forEach(System.out::println);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    刷题:


    题目一:统计数组中元素的个数。
    • 统计一个数组中每个元素及对应元素出现的次数
    • 例如:[a, b, c, a, a, b, d]
    • 结果:{a=3, b=2, c=1, d=1}

    普通解题方式:

    public static void main(String[] args) {
        String[] strArr = {"a", "b", "c", "a", "a", "b", "d"};
        HashMap<String, Integer> map = new HashMap<>(8);
        for (String s : strArr) {
            if(map.containsKey(s)){
                map.put(s, map.get(s) + 1);
            } else {
                map.put(s, 1);
            }
        }
        map.forEach((key, value) -> {System.out.println(key + " : " + value);});
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Steam 流解题方式:

    public static void main(String[] args) {
        String[] strArr = {"a", "b", "c", "a", "a", "b", "d"};
        Stream.of(strArr)
                .collect(Collectors.toMap(key -> key, value -> 1, Integer::sum)) // Integer::sum 等价于 (a, b) -> a + b
                .forEach((key, value) -> {System.out.println(key + " : " + value);});
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    题目二:统计数组中前k个高频元素。
    public static void main(String[] args) {
        String[] strArr = {"a", "d", "c", "d", "d", "b", "a"};
        List<Map.Entry<String, Integer>> list = Stream.of(strArr)
                            // 统计流中相同元素及数量,装成 Map 集合
                            .collect(Collectors.toMap(key -> key, value -> 1, Integer::sum))
                            // 将 Map 集合转换成 Set 集合(因为Map集合不能转成Stream流,需要先转成Collection集合后才可以)
                            .entrySet()
                            // 将 Set 集合转成 Stream 流
                            .stream()
                            // 降序排序
                            .sorted((c1, c2) -> c2.getValue().compareTo(c1.getValue()))  //降序排序
                            //.sorted((c1, c2) -> c1.getValue().compareTo(c2.getValue()))  //升序排序
                            // 截取前面两个元素
                            .limit(2)
                            // 转成 List 集合
                            .collect(Collectors.toList());
        System.out.println(list.toString());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    题目三:有6个用户,筛选:
    • id 为偶数 (过滤)
    • 年龄大于23岁(过滤)
    • 用户名转为大写字母(转换)
    • 用户名倒着排序(排序)
    • 只输出两个用户(截断)

    题目要求:一分钟内完成此题,并且只能使用一行代码实现。

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class User {
        private int id;
        private String name;
        private int age;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    import java.util.Arrays;
    import java.util.List;
    
    public class Test {
    
        public static void main(String[] args) {
            User u1 = new User(1, "a", 21);
            User u2 = new User(2, "b", 22);
            User u3 = new User(3, "c", 23);
            User u4 = new User(4, "d", 24);
            User u5 = new User(5, "e", 25);
            User u6 = new User(6, "f", 26);
            // 将数组变成一个列表集合
            List<User> list = Arrays.asList(u1, u2, u3, u4, u5, u6);
    
            // Stream流式计算、lambda表达式、函数式接口 和 链式编程
            list.stream()
                    // 过滤
                    .filter(user -> {return user.getId()%2==0;})
                    // 过滤
                    .filter(user -> {return user.getAge()>21;})
                    // 转换
                    .map(user -> {return user.getName().toUpperCase();})
                    // 排序
                    .sorted((user1, user2)->{return user2.compareTo(user1);})
                    // 截断
                    .limit(2)
                    // 遍历
                    .forEach(System.out::println);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
  • 相关阅读:
    AI 换装之OOTDiffusion
    理论修炼---初窥Android IPC机制
    如何在TIA博途中在线更新PLC的CPU固件版本?
    并购交易:私募基金CSP将以1.74亿美元收购纽交所上市公司Startek
    Kubernetes 1.25 中的删除和主要变化
    【新学期、新Flag】例文:我的新学期Flag
    Spring之更便捷的读取和存储对象
    分享购是什么?分享购商业模式剖析解读
    React中useEffect Hook使用纠错
    条码二维码读取设备在医疗设备自助服务的重要性
  • 原文地址:https://blog.csdn.net/weixin_42950079/article/details/126326826