Java 8 Stream 流详解

Posted 思想累积

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 8 Stream 流详解相关的知识,希望对你有一定的参考价值。

1、stream 简介

Java 8 中有两个重要的改变,一个是 Lambda 表达式,另外一个是 Stream API(java.util.stream.*)

Stream 流的特点:

  • stream 流不会改变数据源,一般会产生一个新的集合来存储按照我们特定规则计算后的结果
  • stream 会延迟执行,在调用终端操作时中间操作才会执行

1.1 stream 在 java 中的定义:

// 支持顺序和并行聚合操作的元素序列
A sequence of elements supporting sequential and parallel aggregate operations. 

// 以下示例演示了使用Stream和IntStream的聚合操作:    
The following example illustrates an aggregate operation using Stream and IntStream:

// 示例:
int sum = widgets.stream()
    .filter(w -> w.getColor() == RED)
    .mapToInt(w -> w.getWeight())
    .sum();

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定希望对集合进行的操作,可以执行复杂的查找、过滤和映射数据等操作

1.2 Stream 流接口继承关系

最上面的 AutoCloseable 这个接口只有一个方法

void close() throws Exception;

这个方法关闭调用对象,释放可能占用的所有资源。在带资源的try语句的末尾,会自动调用该方法,不用显式调用close()方法

BaseStream 接口:

BaseStream 这个接口是 Stream 流的基类,这个类定义了 Stream 流的主要行为

public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable 
    //获得流的迭代器(终端操作)
    Iterator<T> iterator();
    // 获取流的并行迭代器(终端操作)
    Spliterator<T> spliterator();
    // 并行流返回true,顺序流返回false
    boolean isParallel();
    // 返回一个顺序流(中间操作)
    S sequential();
    // 返回一个并行流(中间操作)
    S parallel();
    // 返回一个无序流(中间操作)
    S unordered();
    // 关闭流时调用,返回一个新流
    S onClose(Runnable closeHandler);
    // 父类 AutoCloseable 关闭流的方法
    @Override
    void close();

1.3 中间操作和终端操作

Stream 流上的操作可以分为 中间操作(Intermediate)和终端操作(Terminal)

中间操作

  • 中间操作会产生一个新的 Stream 流,可以多个中间操作叠加
  • 中间操作不是立即发生的,而是延迟发生的,中间操作创建的新流执行完终端操作后才会发生

终端操作

  • 终端操作返回我们最终需要的数据,只能有一个终止操作

2、Stream 流使用

2.1 Stream 流创建

  1. 通过 Collection 接口的 stream() 或者 parallelStream() 方法创建

    List<String> list = Arrays.asList("1", "2", "3");
    // 创建普通流,主线程按顺序对流进行操作
    Stream<String> stream1 = list.stream();
    // 创建并行流,多线程并行对流进行操作
    Stream<String> stream2 = list.parallelStream();
    // 使用 parallel() 将顺序流转换为并行流
    Stream<String> stream8 = stream1.parallel();
    
  2. 使用 Stream 的静态方法

    Stream<String> stream3 = Stream.empty();
    Stream<String> stream4 = Stream.of("1", "2", "3");
    // 将两个流连接起来
    Stream<String> stream5 = Stream.concat(stream1, stream2); 
    ... ...
    Stream.generate();
    Stream.iterate();
    
  3. 使用 Arraysstream() 方法

    int[] arr = 1, 2, 3;
    IntStream stream = Arrays.stream(arr);
    

2.2 Stream 流中间操作(Intermediate)

  1. filter(Predicate):筛选,结果为 false 的元素会过滤掉

    List<String> list = Arrays.asList("1", "2", "3", "4", "5");
    // 筛选等于 "3" 的第一个元素
    Optional<String> first = list.stream().filter(x -> x == "3").findFirst();
    System.out.println(first.get()); // 输出结果:3
    
  2. map:映射

    1. map(fun):转换元素的值,一个流的元素按函数处理后映射为新的元素

      List<String> list = Arrays.asList("he", "ha", "hia", "hua");
      // 所有元素大写
      list.stream().map(x -> x.toUpperCase()).forEach(System.out::println);
      // 输出结果:HE HA HIA HUA
      
    2. flatMap(fun):流中的每个值都换成另外一个流,再将所有的流连接成一个

      List<String> list = Arrays.asList("h-e", "h-a", "h-i-a", "h-u-a");
      List<String> collect = list.stream().flatMap(x -> Arrays.stream(x.split("-"))).collect(Collectors.toList());
      System.out.println(collect);
      // 输出结果:[h, e, h, a, h, i, a, h, u, a]
      
  3. limit(n):截取,保留 n 个元素

    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 2, 3, 6);
    // 保留 3 个元素
    list.stream().limit(3).forEach(System.out::println);
    // 输出结果:1 2 3
    
  4. skip(n):跳过,跳过 n 个元素

    List<String> list = Arrays.asList("1", "2", "3", "4", "5", "3");
    // 跳过 3 个元素筛选等于 "3" 的第一个元素
    Optional<String> first = list.stream().skip(3).filter(x -> x == "3").findFirst();
    System.out.println(first); // 输出结果:3
    
  5. distinct():去重,去除重复元素

    List<String> list = Arrays.asList("1", "2", "3", "4", "5", "3");
    // 去重遍历
    list.stream().distinct().forEach(System.out::println);
    
  6. sorted:排序自然排序

    List<Integer> list = Arrays.asList(5, 2, 3, 4, 5, 2, 3, 6);
    // 去重并排序
    List<Integer> collect = list.stream().distinct().sorted().collect(Collectors.toList());
    System.out.println(collect);
    

2.3 Stream 流终止操作(Terminal)

  • foreach:遍历

    List<String> list = Arrays.asList("he", "ha", "hia", "hua");
    // 遍历输出
    list.stream().forEach(x -> 
        System.out.println(x);
    );
    // 结果:he ha hia hua
    
  • find

    List<String> list = Arrays.asList("1", "2", "3", "4", "5");
    // 筛选等于 "3" 的第一个元素
    Optional<String> first = list.stream().filter(x -> x == "3").findFirst();
    System.out.println(first.get()); // 输出结果:3
    
  • count()

    List<String> list = Arrays.asList("1", "2", "3", "4", "5", "3");
    // 等于 "3" 的元素的数量
    long count = list.stream().filter(x -> x == "3").count();
    System.out.println(count); // 输出结果:2
    
  • max(Comparator)

    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 2, 3, 6);
    // 集合中最大的元素
    Optional<Integer> max = list.stream().max(Integer::compareTo);
    System.out.println(max.get()); // 结果为:6
    
  • min(Comparator)

    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 2, 3, 6);
    // 集合中最小的元素
    Optional<Integer> max = list.stream().min(Integer::compareTo);
    System.out.println(max.get()); // 结果为:1
    
  • reduce:缩减,可以把一个 stream 流缩减成一个值,实现求和、求最值等操作

    • 求和

      // 对集合中的元素求和
      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
      // 第一种求和方式
      Integer sum = list.stream().reduce((x, y) -> x + y).get();
      // 第二种求和方式
      Integer sum2 = list.stream().reduce(Integer::sum).get();
      // 第三种求和方式(集合中的元素求和再加 1)
      Integer sum3 = list.stream().reduce(3, Integer::sum);
      
    • 求最值

      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
      // 求最大值 1
      Optional<Integer> max = list.stream().reduce((x, y) -> x > y ? x : y);
      // 求最大值 2
      Integer sum2 = list.stream().reduce(Integer::max).get();
      
  • collect:收集操作,把 stream 流收集起来,成为一个新的值或者集合

    • toListtoSettoMap

      List<String> list = Arrays.asList("he", "ha", "hia", "hua", null);
      // toList
      List<String> collect = list.stream().filter(Objects::nonNull).collect(Collectors.toList());
      System.out.println(collect); //[he, ha, hia, hua]
      // toSet
      Set<String> set = list.stream().filter(Objects::nonNull).collect(Collectors.toSet());
      System.out.println(set); // [hia, hua, ha, he]
      // toMap
      Map<String, String> map = list.stream().filter(Objects::nonNull).collect(Collectors.toMap(x -> x, x -> x));
      System.out.println(map); // hia=hia, hua=hua, ha=ha, he=he
      
    • 平均值 averagingDoubleaveragingLongaveragingInt

      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
      // 求平均值
      Double average = list.stream().collect(Collectors.averagingDouble(Integer::intValue));
      System.out.println(average);
      
    • 计数 count

      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
      // 求总数
      Long count = list.stream().collect(Collectors.counting());
      System.out.println(count);
      
    • 最值 maxByminBy

      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
      // 求最高值
      Integer max = list.stream().collect(Collectors.maxBy(Integer::compare)).get();
      System.out.println(max);
      
    • 求和 summingIntsummingLongsummingDubbo

      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
      // 求和
      Integer sum = list.stream().collect(Collectors.summingInt(Integer::intValue));
      System.out.println(sum);
      
    • 统计所有 summarizingIntsummarizingLongsummarizingDouble

      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
      // 统计所有信息
      DoubleSummaryStatistics collect = list.stream().coll

      以上是关于Java 8 Stream 流详解的主要内容,如果未能解决你的问题,请参考以下文章

      java 8 Stream(流)

      Java--Stream流详解

      Java Stream流(详解)

      Java8 Stream 流详解

      TS Stream 详解

      Java 8 的Stream流那么强大!