Java Stream流

a sequence of elements from source that supports aggregate operations

1. 概述

流不存储元素,可以根据需要进行计算转换

pipelining:很多流的操作也是返回一个流

internal iteration:流操作进行迭代,用户感知不到循环遍历

流的工作流程

  • 创建一个流
  • 指定将流转换为其他流的中间操作,可包括多个步骤(惰性操作)
  • 应用终止操作,从而产生结果。这个操作会强制执行之前的惰性操作。这个步骤以后,流就再也不用了。

2. 流的创建

  • 1、Collection接口的stream方法

    Stream<String> as = new ArrayList<String>().stream();

  • 2、Arrays.stream可以将数组转为Stream

    Stream<String> b = Arrays.stream("a,b,c,d,e".split(","), 3, 5);

  • 3、利用Stream类进行转化

    • of方法,直接将数组转化

      Stream<Integer> c = Stream.of(new Integer[5]);

    • empty方法,产生一个空流

      Stream<String> d = Stream.empty();

    • generate方法,接收一个Lambda表达式

      Stream<String> e1 = Stream.generate(() -> "hello");

      Stream<Double> e2 = Stream.generate(Math::random);

    • iterate方法,接收一个种子和一个Lambda表达式

      Stream<BigInteger> e3 = Stream.iterate(BigInteger.Zero, n -> n.add(BigInteger.ONE));

  • 4、基本类型流(只有三种)

    • IntStream

      IntStream s = IntStream.of(1,2,3,4,5);
      Stream<Integer> s1 = s.boxed();
      IntStream s2 = s1.mapToInt(Integer::intValue);
      
    • LongStream

    • DoubleStream

  • 5、并行流

    使得所有的中间转换操作都将被并行化,需要保证传给并行流的操作不存在竞争

    • Collections.parallelStream()将任何集合转为并行流

    • Stream.parallel()方法,产生一个并行流

      IntStream s1 = IntStream.range(1, 100000);
      long evenNum = s1.parallel().filter(n->n%2==0).count();
      
  • 6、其他类/方法产生Stream流

    • Files.lines方法

      Stream<String> contents = Files.lines(Paths.get("abc.txt"));

    • Pattern的splitAsStream方法

      Stream<String> words = Pattern.compile(",").splitAsStream("a,b,c");

3. 流的转换

3.1 过滤filter

接收一个Lambda表达式,对每个元素进行判断,符合条件留下

Stream<Integer> s = Stream.of(1,2,3,4,5).filter(n -> n>2);

3.2 去重distinct

对流的元素进行过滤,去除重复,只留下不重复的元素

Stream<Integer> s = Stream.of(1,2,3,4,5).distinct();

对象的判断,先调用hashCode方法,再调用equals方法

3.3 排序sorted

  • 对流的基本类型包装类元素进行排序

    Stream<Integer> s = Stream.of(1,2,3,4,5).sorted();

  • 提供Comparator,对流的元素进行排序
    Stream.of(planets).sorted(Comparator.comparing(String::length));

  • 对流的自定义对象元素进行排序,调用对象的compareTo方法

3.4 转化

  • 1、map

    • 利用Lambda表达式对流的每个元素进行函数计算

      Stream<Integer> s = Stream.of(1,2,3,4,5).map(n->n*n);

    • 利用方法引用,对流每个元素进行函数计算并返回Stream

      Stream<Stream<String>> allLetters = Stream.of(planets).map(word->letters(word));

    • 利用方法引用,对流每个元素进行函数计算返回Stream,并合并

      Stream<String> allLetters = Stream.of(planets).flatMap(word->letters(word))

      flatMap执行一对多的转换,然后将所有的Map都展开。

  • 2、抽取limit

    Stream<Integer> s = Stream.of(1,2,3,4,5).limit(3);

  • 3、跳过skip

    Stream<Integer> s = Stream.of(1,2,3,4,5).skip(3);

  • 4、连接concat

    Stream<String> s = Stream.concat(s1, s2);

  • 5、额外调试peek

    Stream<Double> s = Stream.iterate(1.0, n->n*2).peek(n->System.out.println(n)).limit(5);

3.5 总结

  • 流的转换从要给流得到另外一个流
  • 一个流只能使用一次
  • 转换过程,需要使用类本身的方法,如compareTo,hashCode,equals等方法

4. Optional类型

optionnal是数据对象容器,用来解决NullPointerException的一把钥匙,在流运算中避免对象是否为null的判定。

4.1 创建

  • of方法
  • empty方法
  • ofNullable方法,对于对象有可能为null情况,安全创建

4.2 使用

直接使用get方法,容易引发NoSuchElementException一场

5. 流的计算

5.1 简单约简(聚合函数)

  • count(),计数
  • max(Comparator),最大值
  • min(Comparator),最小值
  • findFirsrt,找到第一个元素
  • findAny(),找到任意一个元素
  • anyMatch(Predicate),任意元素满足条件返回true
  • allMatch(Predicate),所有元素满足条件返回true
  • noneMatch(Predicate),没有元素满足条件返回true

5.2 自定义约简

  • reduce,传递一个二元函数BinaryOperator,对流元素进行计算,如求和、求积、字符串连接等

    Optional<Integer> sum = s.reduce(Integer::sum);
    Optional<Integer> product = s1.reduce((x,y)->x*y);
    Optional<Integer> product1 = s2.reduce(1, (x,y)->x*y);
    

5.3 查看/遍历元素

  • iterator(),遍历元素,返回迭代器
  • forEach(Consumer),应用一个函数到每个元素上

5.4 存放到数据结构中

  • toArray
  • collect(Collectors.toList())
  • collect(Collectors.toSet())
  • collect(Collectors.toMap())
  • collect(Collectors.joining()),将结果连起来

5.5 高阶计算

  • 分组groupingBy和分区partitionBy
  • 分组后的约简
    • counting
    • summing
    • maxBy
    • minBy

5.6 总结

  • 流的最终运算结果
  • 惰性计算,启动先前的转换环节
  • 三种结果:约简、遍历/查看、转存为其他的数据结构
posted @ 2022-05-04 22:29  hunter-w  阅读(185)  评论(0编辑  收藏  举报