Java基础 : Stream

6 阅读4分钟

Stream流

Function 接口 : 用于类型函数转换,就是apply

        // 表示将x 乘2 得到另外一个整数
        Function<Integer, Integer> multiple2 = x -> x * 2;
        // +100
        Function<Integer, Integer> add100 = x -> x + 100;
        // compose 接口表示,先对x执行add100,再对结果执行multiple2
        Integer apply = multiple2.compose(add100).apply(2);
        System.out.println(apply);
        // 先乘2 再执行add100
        System.out.println(multiple2.andThen(add100).apply(2));
        // identity : 恒等函数,就是输出原值,没啥意义
        Integer x=900;
        System.out.println(System.identityHashCode(x));
        Object apply1 = Function.identity().apply(x);
        System.out.println(System.identityHashCode(apply1));

Optional 是一个容器类,用于包装可能为空的对象,避免直接返回 null

       // optional:通过显式的 API 操作,减少 NullPointerException 的发生
        String s = null;
        Optional<String> optional = Optional.ofNullable(s);
        //  map返回一个optional对象,当optional为空时,不会执行对应方法map方法
        // orElse表示如果optional对象为空,则返回0
        int i = optional.map(String::length).orElse(0);
        System.out.println(i);
        // 链式编程:避免判空操作
        i = Optional.ofNullable(s).map(String::length).orElse(0);
        System.out.println(i);
        // orElseGet:如果optional对象为空,则调用函数获取值,Supplier接口就一个抽象方法get()
        Optional.ofNullable(s).map(String::length).orElseGet(() -> 90);

Stream流操作:

  • 中间操作(Intermediate Operations): 通常返回流
    • 无状态(Stateless)操作:每个数据的处理是独立的,不会影响或依赖之前的数据。如 filter()flatMap()map()peek()unordered()

      // filter ==> 传入一个Predicate对象,重写test方法,test方法内部用于筛选元素 , 返回一个新流// flatMap: 将多个流(集合),展开成一个新的流 ==> 合并多个List
          List<List<String>> listOfLists = Arrays.asList(
                      Arrays.asList("a", "b"),
                      Arrays.asList("c", "d"),
                      Arrays.asList("e", "f")
              );
              Stream<Object> objectStream = listOfLists.stream().flatMap(new Function<List<String>, Stream<?>>() {
                  @Override
                  public Stream<?> apply(List<String> strings) {
                      return strings.stream();
                  }
              });
              objectStream.forEach(System.out::println);
      // map : 对流中数据类型进行转换,得到新的流
              List<String> strings = Arrays.asList("1", "2", "3");
              List<Integer> integers = strings.stream()
                      .map(new Function<String, Integer>() {
                          @Override
                          public Integer apply(String s) {
                              return Integer.parseInt(s);
                          }
                      })
                      .collect(Collectors.toList());
      // peek():类似于foreach,不会改变流,同时只有终止操作触发才会执行,通常用于测试 ,unordered()用于声明流是无序的对list速度可能会加快
      
    • 有状态(Stateful)操作:处理时会记录状态,依赖前一个处理。如 distinct()sorted(comparator)limit()skip()

      // distinct 去重
      Stream.of(1, 2, 3,5,6,7,4,3,3)
            .distinct() // 基于equals进行判断是否去重
            .forEach(x -> System.out.println("distinct: " + x));
      ​
      // sorted 排序
      Stream.of(1, 2, 3,5,6,7,4,3,3).sorted(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                 return o2-o1;
            }
      }).forEach(x -> System.out.println("sorted: " + x));
      ​
      // limit :取前n个
      Stream.of(1, 2, 3,5,6,7,4,3,3).limit(3)
            .forEach(x -> System.out.println("limit: " + x));
      ​
      // skip : 跳过前n个
      Stream.of(1, 2, 3,5,6,7,4,3,3).skip(3)
            .forEach(x -> System.out.println("skip: " + x));
      
  • 终止操作(Terminal Operations): 无返回值
    • 非短路操作:处理完所有数据才能得到结果。如 collect()forEach()forEachOrdered()max()min()reduce()等。

      // collect:收集,转为集合类型,分组等操作
            List<Integer> collect1 = Stream.of(1, 2, 3, 5, 6, 7, 4, 3, 3).collect(Collectors.toList()); // 转链表
              Map<Integer, Integer> collect2 = Stream.of(1, 2,  5, 6, 7, 4, 3).collect(Collectors.toMap(x -> x, x -> x * 2)); // 映射成map,x不能重复
              Map<Integer, List<Integer>> collect3 = Stream.of(1, 2, 3, 5, 6, 7, 4, 3, 3).collect(Collectors.groupingBy(x -> x % 2)); // 按照 模2 分组
              collect3.entrySet().forEach(x -> System.out.println(x.getKey() + ":" + x.getValue()));
      ​
      // forEach 传入一个Consumer实现即可, forEachOrdered() 用于并行流处理后结果,保证按照原始顺序输出// max,min 求极值
              Optional<Integer> max1 = Stream.of(1, 2, 3, 5, 6, 7, 4, 3, 3).max(new Comparator<Integer>() {
                  @Override
                  public int compare(Integer o1, Integer o2) {
                      return o2 - o1;
                  }
              });
      // reduce : apply的第一个参数是求和就是合并后的结果
              System.out.println(max1.get());
              Stream.of(1, 2, 3, 5, 6, 7, 4, 3, 3).reduce(new BinaryOperator<Integer>() {
                  @Override
                  public Integer apply(Integer integer, Integer integer2) {
                      System.out.println("integer:" + integer + " integer2:" + integer2);
                      return integer + integer2;
                  }
              });
      
    • 短路(short-circuiting)操作:拿到符合预期的结果就会停下来,不一定会处理完所有数据。如 anyMatch()allMatch()noneMatch()findFirst()findAny() 等。

        // anyMatch 存在一个匹配的元素
        boolean b = Stream.of(1, 2, 3, 5, 6, 7, 4, 3, 3).anyMatch(new Predicate<Integer>() {
                  @Override
                  public boolean test(Integer integer) {
                      return integer == 3;
                  }
              });
              
      // allMatch() 所有的都要匹配, noneMatch  一个都不匹配, findFirst 获取首个元素(适用于有序的流), findAny 返回任意一个元素
      

并行流:底层用了ForkJoinPool,ForkJoinPool将任务拆分成多个小任务,然后分散到不同线程中执行,每个线程都有自己的任务队列,当某个线程空闲时会从其他线程的任务队列窃取任务执行,充分发挥了cpu的性能

如果是IO密集型任务,线程阻塞这段时间cpu的性能是没有利用到的,从而io密集型任务不适合ForkJoinPool

 Stream.of(1, 2, 3, 5, 6, 7, 4, 3, 3).parallel().forEach(System.out::println); // 不是按照顺序输出

创建流

// 串行流
    // 从集合中创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream(); // 创建串行流
    // 数组中创建
String[] array = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(array);
​
// 并行流
    // 从集合中创建
List<String> list = Arrays.asList("a", "b", "c", "d");
Stream<String> parallelStream = list.stream().parallel();
​
    // 从普通流中创建
List<String> list = Arrays.asList("a", "b", "c", "d");
Stream<String> parallelStream = list.stream().parallel();