stream.md 9.3 KB


title: Java流库详解(java.util.stream) date: 2020-07-06 12:00:00 tags: Java cover: https://static.jqwei.com/blog/img/IMG_3460.PNG

categories: 编程语言

流提供了一种让我们可以在比集合更高的概念级别上指定计算的数据视图。通过使用流,我们可以说明想要完成什么任务,而不是说明如何去实现它。(这一点受益于lambda表达式)我们将操作的调度留给具体的实现去解决。

流大量的用到了lambda表达式(同根生于Java8)之后的篇幅将会说到lambda表达式

一、 流的特点

二、 流的创建

JavaAPI中有大量方法都可以产生流

三、 filter、map和flatMap方法

流的转换会产生一个新的流,它的元素派生自另一个流中的元素。

  • Stream<t> filter(Predicate<? super T> predicate)</t> 产生一个流,它包含当前流中所有满足断言条件的元素。
  • <r> Stream<r> map (Function<? super T,? extends R> mapper)</r></r> 产生一个流,它包含将mapper应用于当前流中所有元素产生的结果。 注1:如果返回值是流,则返回流的流(准确来说返回R就是R的流) 注2:R和T的意思。R为返回值,所以返回值需要是R的子类。T是入参(原有Stream
  • <r> Stream<r> flatMap (Function<? super T,? extends Stream<? extends R>> mapper)</r></r> 产生一个流,它是通过将mapper应用于当前流中所有元素所产生的结果连接到一起而获得的。 注意:这里的每个结果都是一个流。

四、 抽取子流和连接流

例如:

Stream<double> stream = Stream.generate(Math::random).limit(100L);
stream.forEach(System.out::println);
</double>

例如:取前200自然数,然后去掉前100个

Stream<integer> stream = Stream.iterate(1, (n)->n+1);
stream = stream.limit(200).skip(100);
stream.forEach(System.out::println);
</integer>

例如:

Stream<? extends Object> result = Stream.concat(stream, stream2);
result.forEach(System.out::println);

注意:第一个流不应该是无限的,否则第二个流永远都不会得到处理的机会。

  • Stream<t> limit(Long maxSize)</t> 产生一个流,其中包含了当前流中最初的maxSize个元素。
  • Stream<t> skip(Long n)</t> 产生一个流,它的元素时当前流中除了前n个元素之外的所有元素。
  • static <t> Stream<t> concat(Stream<? extends T> a, Stream<? extends T> b)</t></t> 产生一个流,它的元素时a的元素后面跟着b的元素。

五、 其他的流转换

  • Stream<t> distinct()</t> 产生一个流,包含当前流中所有不同元素。
  • Stream<t> sorted()</t>
  • Stream<t> sorted(Comparator<? super T> comparator)</t> 产生一个流,它的元素时当前流中的所有元素按照顺序排列的。第一个方法要求元素是实现了Comparable类的实例。
  • Stream<t> peek(Comsumer<? super T> action)</t> 产生一个流,它与当前流中的元素相同,在获取其中每个元素时,会见其传递给action。

六、 简单约简(重要)

约简是一种终结操作(terminal operation),它们会将流约简为可以在程序中使用的非流值

  • Optional<t> max(Comparator<? super T> comparator)</t>
  • Optional<t> min(Comparator<? super T> comparator)</t> 分别产生这个流的最大元素和最小元素,使用由给定比较器定义的排序规则,如果这个流为空,会产生一个空的Optional对象。这些操作都是终结操作。
  • Optional<t> findFirst()</t>
  • Optional<t> findFirst()</t> 分别产生这个流的第一个和任意一个元素,如果这个流为空,会产生一个空的Optional对象。这些操作都是中介操作。
  • boolean anyMatch(Predicate<? super T> predicate)
  • boolean allMatch(Predicate<? super T> predicate)
  • boolean noneMatch(Predicate<? super T> predicate) 分别在这个流中任意元素、所有元素和没有任何元素匹配给定断言时返回true。这些操作都是终结操作。

七、 收集结果

八、 收集到映射表中(Map)

  • static<t,k,u,m extends map<k,u>> Collector<t,?,m> toMap(Function<? supper T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<u> mergeFunction, Supplier<m> mapSupplier)</m></u></t,?,m></t,k,u,m>
  • static<t,k,u,m extends concurrentmap<k,u>> Collector<t,?,m> toConcurrentMap(Function<? supper T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<u> mergeFunction, Supplier<m> mapSupplier)</m></u></t,?,m></t,k,u,m> 产生一个收集器,它会产生一个映射表(Map)或并发映射表(ConcurrentMap)。keyMapper和valueMapper函数会应用到每个收集到的元素上,从而在所产生的映射表中生成一个键/值项。默认情况下,当两个元素产生相同的键时,会抛出一个IllegalStateException异常。你可以提供一个mergeFunction来合并具有相同键的值。默认情况下,其结果是一个HashMap或ConcurrentHashMap。你可以提供一个mapSupplier,它会产生所期望的映射表实例。 > 注,最后的两个参数(mergeFunction,mapSupplier)可以没有,API中也提供了没有这俩个参数的函。

九、 群组和分区

  • static <t,k> Collector<t,?,map<k,list<t>>> groupingBy(Function<? super T,? extends K> classifier)</t,?,map<k,list<t></t,k>
  • static <t,k> Collector<t,?,concurrentmap<k,list<t>>> groupingByConcurrent(Function<? super T,? extends K> classifier)</t,?,concurrentmap<k,list<t></t,k> 产生一个收集器,它会产生一个映射表或并发映射表,其键是将classifier应用于所有收集到的元素上所产生的结果,而值是由具有相同键的元素构成的一个个列表。
  • static <t> Collector<t,?,map<boolean,list<t>>> partitioningBy(Preditcate<? super T> predicate)</t,?,map<boolean,list<t></t> 产生一个收集器,它会产生一个映射表,其键是true/false,而值是由满足/不满足断言的元素构成的列表。

十、 下游收集器

Collectors提供了很多强大的功能,其中下游收集器可以让我们轻松(可能吧)地处理下游数据(Map

作为下游收集器,可以直接在groupingBy方法中使用,例如:

Stream<double> stream = Stream.generate(Math::random).limit(10000L).map((k)->k*10);
Map<integer, long> collect = stream.collect(Collectors.groupingBy((k)->{return k.intValue();},Collectors.counting()));
collect.forEach((k,v)->System.out.println("K:"+k+"  V:"+v));
</integer,></double>
  • static <t> Collector<t,?,long> counting()</t,?,long></t> 产生一个可以对收集到的元素进行计数的收集器。
  • static<t> Cikkectir<t,?,integer> summingInt(ToIntFunction<? super T> mapper)</t,?,integer></t>
  • static<t> Cikkectir<t,?,long> summingLong(ToLongFunction<? super T> mapper)</t,?,long></t>
  • static<t> Cikkectir<t,?,double> summingDouble(ToIntFunction<? super T> mapper)</t,?,double></t> 产生一个收集器,对将mapper应用到收集到的元素上之后产生的值计算总和。 例如:
Map<integer, integer> collect2 = stream.collect(Collectors.groupingBy((k)->{return k.intValue();},Collectors.summingInt((k)->k.intValue())));
collect2.forEach((k,v)->System.out.println("K:"+k+"   V:"+v));
// &#x8FD9;&#x5C06;&#x4EA7;&#x751F;&#x4EE5;0-9&#x5206;&#x5F00;&#x7684;10&#x5404;&#x7EC4;&#xFF0C;v&#x4E3A;&#x6BCF;&#x4E2A;&#x7EC4;&#x4E2D;&#x6240;&#x6709;&#x6570;&#x7684;&#x5408;
</integer,>
  • static <t> Collector<t,?,optional<t>> maxBy(Comparator<? super T> comparator)</t,?,optional<t></t>
  • static <t> Collector<t,?,optional<t>> minBy(Comparator<? super T> comparator)</t,?,optional<t></t> 产生一个收集器,使用comparator指定的排序方法,计算收集到的元素中的最大值和最小值。
  • static <t,u,a,r> Collector<t,?,r> mapping(Function<? super T,? extends U> mapper, Collector<? super U,A,R> downstream)</t,?,r></t,u,a,r> 产生一个收集器,它会产生一个映射表,其键是将mapper应用到收集到的数据上而产生的,其值是使用downstream收集器收集到的具有相同键的元素。

十一、 约简操作

reduce方法是一种用于从流中计算某个值的通用机制,其最简单的形式将接受一个二元函数,并从前两个元素开始持续应用它。

注意:如果收集操作是并行的,reduce就不是线程安全的,小心使用。

  • Optional<t> reduce(BinaryOperator<t> accumulator)</t></t>
  • T reduce(T identity, BinaryOperator<t> accumulator)</t>
  • <u> U reduce(U identity,BiFunction<u, ? super t, u> accumulator,BinaryOperator<u> combiner)</u></u,></u> > 注意:如果reduce是并行流,那么reduce会产生多个结果,需要提供第二个函数(组合器)将结果合并。 用给定的accumulator函数产生流中元素的积累总和。如果提供了幺元,那么第一个被累计的元素就是该幺元。如果提供了组合器,那么它可以用来将分别累计的各个部分整合成总和。例如:
int result = words.reduce(0,(total,word)->total+word.length(), (total1, total2)->total1+total2);
  • <r> R collect(Supplier<r> supplier, BiConsumer<r, ? super t> accumulator, BiConsumer<r, r> combiner)</r,></r,></r></r> 将元素收集到类型R的结果中。在每个部分上,都会调用cupplier来提供初始结果,调用accumulator来交替的将元素添加到结果中,并调用combiner来整合两个结果。

原文地址: https://www.jianshu.com/p/937d38e856c8