# Java Stream流

# 参阅

Java 8 中的 Streams API 详解 (opens new window) Java 8中Stream API的这些奇技淫巧! (opens new window)

# 使用流

# 构造的方式

  1. 构造流的基本方式(如何获得流)
// 通过Collection的stream方法构造
Stream<?> stream = list.stream();
// Arrays.stream构造各种类型的数组流
Stream<String> stream = Arrays.stream(new String[]{"a", "b", "c"});
// 通过Stream.of创建任意数量的流
Stream<String> stringStream = Stream.of("a", "b");
  1. 构造数值流 使用IntStream和LongStream的静态方法构造数值流,range不包含结束值。
// 筛选出1-100中的偶数
int count = IntStream.rangeClosed(1,100).filter(n->n%2==0).count;
  1. 流转换为其他数据类型(如何从流转换成需要的数据类型)

  2. 由文件生成流 java.nio.file.Files提供了很多返回流的静态方法

  3. 由函数生成流 Stream.iterate和Stream.generate可以创建无限流

// Stream.iterate
Stream.iterate(0, n->n+2).limit(10).foreach(System.out::println);
// Stream.generate
Stream.generate(Math.random).limit(5).foreach(System.out::println);
// 生成全是1的无限流
Stream.generate(()->1).limit(5).foreach(System.out::println);

# 操作的方法

流的三类操作方式

  1. Intermediate

  2. Terminal

  3. Short-circuiting

映射

原生 衍生 入参->返回
map mapToInt、mapToLong、mapToDouble Function<T,R> -> Stream[R]
flatmap flatmapToInt、flatmapToLong、flatmapToDouble Function<T,Stream[R]> -> Stream[R]

衍生操作的作用:

重点解释flatmap使用:

map的映射关系是1:1的, 但是存在有层级结构的Stream, 需要使用flatM ap使其扁平化(将最底层元素抽出来放到一起)

Stream<List<Integer>> inputStream = Stream.of(
 Arrays.asList(1),
 Arrays.asList(2, 3),
 Arrays.asList(4, 5, 6)
 );
Stream<Integer> outputStream = inputStream.
flatMap((childList) -> childList.stream());

最终outputStream中没有List了.

筛选

谓词 作用 入参->返回
filter 过滤掉false Predicate[T] -> Stream[T]
distinct 根据hashCode和equals方法去重 () -> Stream[T]
skip 扔掉前n个元素 long -> Stream[T]
limit 返回前n个元素 long -> Stream[T]
peek
foreach 循环 Consumer[T] -> void
sorted 排序 Comparator[T] -> Stream[T]

匹配和查找

操作 作用 入参->返回
anyMatch 至少匹配一个元素 Predicate[T] -> boolean
allMatch 是否匹配所有元素 Predicate[T] -> boolean
noneMatch 没有任何元素匹配 Predicate[T] -> boolean
findAny 返回当前流中任意元素 () -> Optional[?]
findFirst 查找第一个元素 () -> Optional[?]

Match操作都是返回boolean的结果,并且都使用了短路操作,即当anyMatch有一个匹配了就直接返回true,而不再继续匹配了。

findAny和findFirst也都是短路操作,两者在串行使用时效果一致,当并行时请尽量使用findAny,因为其并行限制少(性能好)。

归约

计数、求和都是归约的特殊场景应用。

操作 作用 入参->返回
reduce 归约 BinaryOperator[T] -> Optional[T]
max 求最大值 () -> Optional[T]
min 求最小值 () -> Optional[T]
count 计数 () -> long

收集器(Collectors)

collect、Collectors和Collector的区别:

  • collect是Stream提供的收集操作
  • Collectors是工具类,提供了很多静态方法来返回Collector
  • Collector作为collect方法的参数,用于构造结果集

Collectors类提供的操作:

操作 作用 入参->返回
toList
toSet
toMap
toConcurrentMap
groupingBy 分组 Function<? super T, ? extends K> -> Collector
minBy 求最小值 Comparator<? super T> -> Collector
maxBy 求最大值 Comparator<? super T> -> Collector
counting
joining 连接字符串(通过toString)
mapping
summingInt/Long/Double 汇总/求和 ToIntFunction<? super T>
averagingInt/Long/Double 计算平均数 ToIntFunction<? super T>
summarizingInt/Long/Double 总结(求和/平均数/最大最小值) ToIntFunction<? super T>
reducing 归约
partitioningBy 分区

案例:

计数
> Map<String, Long> map = fruitList.stream().map(Fruit::getName).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

排序
> map.entrySet().stream().sorted(Map.Entry.<String, Long>comparingByValue().reversed()).forEachOrdered(System.out::println);

累加求和
> Map<String, Integer> sumMap = fruitList.stream().collect.(Collectors.groupingBy(Fruit::getName, Collectors.summingInt(Fruit::getPrice)));

分组
> Map<String, List<Fruit>> groupMap = fruitList.stream().collect(Collectors.groupingBy(Fruit::getName));

Collectors.mapping

//group by price, uses 'mapping' to convert List<Fruit> to List<String>
Map<String, List<Integer>> groupMap = fruitList.stream().collect(Collectors.groupingBy(Fruit::getName, Collectors.mapping(Fruit::getPrice, Collectors.toList())));


Collectors.toMap

Stream().count()和collect(Collectors.counting())的区别:

自定义收集器

比较器

Comparator类提供了静态方法来支持

# 数值流

由于基本类型的包装类存在装箱拆箱操作,数据量大会非常影响性能,因此Java 8提供了数值流。

映射为数值流

  • mapToInt
  • mapToDouble
  • mapToLong

案例:

// mapToInt返回IntStream
int ages = list.stream().mapToInt(User::getAge).sum();

转换为对象流

IntStream上的lambda操作只能使用int类型,因此有时需要将其转换为Integer。

案例:

IntStream intStream = list.stream().mapToInt(User::getAge);
Stream<Integer> stream = intStream.boxed();

Stream不会返回为null的集合

# Optianl

数值类型的Optional 当遇到求和的场景,如何区分没有值和为0的场景呢?因此Optional提供了数值类型。

  • OptionalInt
  • OptionalDouble
  • OptionalLong

案例:

OptionlInt maxAge = users.stream().mapToInt(User::getAge).max();
// 如果没有最大值可以显示提供
int max = maxAge.orElse(1);

# 流中用到的函数

# 流的实现原理

修改于: 8/11/2022, 3:17:56 PM