目录

摘要

一、Stream概述

1. 概述

定义

理解

2. 应用

结构

示例

3. Stream方法分类

4. 副作用(Side-effects)

二、资源(Source)

1. 基础创建方法

2. 进阶概念

序列流(Sequential Stream)与并行流(Parallel Stream)

关闭流

三、中间操作 (Intermediate Operation)

distinct

sorted

limit & skip

filter

peek

takeWhile & dropWhile

map, flatMap & mapMulti

flatMap与map的区别

mapMulti与map的区别

四、终端操作 (Terminal Operation)

min & max

count

toArray

noneMatch, allMatch & anyMatch

findAny & findFirst

forEach & forEachOrdered

forEach与forEachOrdered的区别

collect

reduce

参考文章


摘要

Stream流处理器入门第三步——Stream流处理概述(定义、结构、分类、副作用)和方法详解与示例(filter、peek、takeWhile & dropWhile、map & mapMulti & flatMap、forEach & forEachOrdered、collect、reduce)。

如果文中有任何概念上的错误或者理解上的偏差,请务必留言,衷心感谢。


一、Stream概述

1. 概述

定义

一个支持序列和并行的元素序列。

理解

打个汽车生产线的比方,从最开始的各个零部件,经过不同的步骤,最终组装出一台整车。在这个过程中,可以被应用于后续组装过程的各零部件的集合就是我们现在讨论的Stream,不同的组装步骤就是Stream的应用方向,最终生产出的整车,就是我们创建当前Stream的目的。

A sequence of elements supporting sequential and parallel aggregate operations.

2. 应用

结构

  • 一个资源(处理对象):可能是数组、集合、Generator函数、IO通道等等
  • 零或多个中间操作
  • 一个终端操作

A stream pipeline consists of a source (which might be an array, a collection, a generator function, an I/O channel, etc), zero or more intermediate operations (which transform a stream into another stream, such as filter(Predicate)), and a terminal operation (which produces a result or side-effect, such as count() or forEach(Consumer)).

示例

clients.stream().mapToInt(UdacisearchClient::getQuarterlyBudget).sum();

clients是一个集合,这里clients.stream()创建出资源。针对这个资源,先应用名为mapToInt的中间操作,再应用名为sum的终端操作。

3. Stream方法分类

中间操作(Intermediate operations):每次操作返回一个流,可以进行多次中间操作

  • 无状态操作(Stateless):元素处理不受之前元素的影响,可以进行单一元素处理。如filter()、map()、peek()等等。
  • 有状态操作(Stateful):元素处理受之前元素的影响,必须拿到完整元素集合才能开始处理。如sorted()、distinct()、limit()、skip()。

终端操作(Terminal operations):每个流只能进行一个终端操作,执行后流无法再次使用,返回一个新的集合或者对象。

  • 非短路操作(non-short circuit):必须处理所有元素才能得到最终结果。如forEach()、max()、min()、count()、collect()、reduce()、toArray()等等。
  • 短路操作(short circuiting):遇到某些符合条件的元素就可以得到最终结果。如anyMatch()、allMatch()、noneMatch()、findFirst()、findAny()。

关于中间操作和终端操作的理解:

Stream只是一个API,必须将Stream转化为某种数据接口,才能存储结果。如果当前操作不含终端操作,Stream结果将无法被记录,相应操作也不会被真正执行(懒加载)。

4. 副作用(Side-effects)

        主要是一些stream的异常,具体分析可见Java8 Stream的副作用。


二、资源(Source)

1. 基础创建方法

这里借鉴一下其他博主的总结(Java8 Stream流的使用)(稍微做了以下补充),解析得很到位。

// 1.通过集合类的stream()或者parallelStream()方法
List<String> list = Arrays.asList("one", "two", "three");
Stream<String> stream = list.stream();
Stream<String> parallelStream = list.parallelStream();// 2.通过数组的stream()方法
String array = {1,2,3,4,5};
IntStream stream = Arrays.stream(array);// 3.通过Stream的静态方法
Stream<Character> charStream = Stream.of('a','b','c');                //a,b,c
Stream<Character> emptyStream = Stream.empty();                       //创建空Stream
Stream<Integer> intStream = Stream.iterate(0, (x) -> x + 1).limit(5); //0,1,2,3,4
Stream<Double> doubleStream = Stream.generate(Math::random).limit(5);
Stream.concat(charStream, charStream);                                //a,b,c,a,b,c// 4.通过BufferedReader.lines()方法将每行的内容转换成流
BufferedReader reader = new BufferedReader(new FileReader("C:\\file.txt"));
Stream<String> lineStream = reader.lines();// 5.通过Pattern.splitAsStream()方法将字符串转换成流
Pattern pattern = Pattern.compile(",");
Stream<String> stringStream = pattern.splitAsStream("a,b,c,d,e");
————————————————
版权声明:本文为CSDN博主「千筠Wyman」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sinat_36645384/article/details/121494363

此外,Stream静态方法还包含 ofNullable 方法,虽然最终返回的都是Stream流,但和 of 方法用途不太一样,因为 ofNullable 方法只有一个输入。当此输入为null时,返回一个空的Stream;否则,返回仅包含此元素的Stream。原则上来说ofNullable方法也是创建stream的静态方法之一,但实际上其主要用于判空,详细了解可以看这里(Java 8 中的 Optional 的优点究竟在哪里?)。

public String getName(User user){return Optional.ofNullable(user).map(u -> u.name).orElse("Unknown");
}

2. 进阶概念

序列流(Sequential Stream)与并行流(Parallel Stream)

Stream流分为序列流和并行流,默认创建为序列流。序列流为单线程,并行流为多线程。因此并行流只能用于对处理顺序没有要求的任务

//创建时定义
Stream sequentialStream = Collection.stream();          //创建序列流(创建时默认为序列流)
Stream parallelStream = Collection.parallelStream();    //创建并行流//创建后定义
sequentialStream.parallel();                            //序列流并行化
parallelStream.sequential();                            //并行流序列化//序列与并行的查询
System.out.println(sequentialStream.isParallel());      //True
System.out.println(parallelStream.isParallel());        //False

关闭流

大多数情况下,Stream不需要被关闭。只有当Stream的处理对象为IO通道时才需要考虑关闭,相关方法为 close()

Streams have a close() method and implement AutoCloseable. Operating on a stream after it has been closed will throw IllegalStateException. Most stream instances do not actually need to be closed after use, as they are backed by collections, arrays, or generating functions, which require no special resource management. Generally, only streams whose source is an IO channel, such as those returned by Files.lines(Path), will require closing. If a stream does require closing, it must be opened as a resource within a try-with-resources statement or similar control structure to ensure that it is closed promptly after its operations have completed.


三、中间操作 (Intermediate Operation)

distinct

Stream.of(1,1,1,1,1,2,2).distinct()               //1,2.forEach(System.out::println);

sorted

Stream.of(10,2,9,4,5,0,18).sorted()               //0,2,4,5,9,10,18.forEach(System.out::println);

limit & skip

limit定义:返回一个长度不超过输入值的的当前Stream。

Returns a stream consisting of the elements of this stream, truncated to be no longer than {@code maxSize} in length.

skip定义:返回一个放弃输入数量元素的当前Stream。

Returns a stream consisting of the remaining elements of this stream after discarding the first {@code n} elements of the stream.

Stream.of(1,2,3,4,5,6,7,8).skip(2)             //3,4,5,6,7,8.limit(3)            //3,4,5.forEach(System.out::println);

filter

筛选方法,输入为Predicate

Stream.of(10,2,9,4,5,0,18).filter(s -> s>=10)               //10,18.forEach(System.out::println);

peek

peek定义:返回包含当前所有元素的Stream(不做任何更改),随后当元素从所产生的流中被消耗时,附加地对每个元素执行所提供的动作。

Returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.

理解:此方法主要用于支持调试,当您希望在元素流经管道中的某个点时查看这些元素(相当于一个中间操作版的forEach() )。

Stream.of("one", "two", "three", "four").filter(e -> e.length() > 3).peek(e -> System.out.println("Filtered value: " + e)).map(String::toUpperCase).peek(e -> System.out.println("Mapped value: " + e)).collect(Collectors.toList());

运行结果

强烈建议尝试下此例,从结果的打印顺序可以加深对Stream的流式理解。另,如果注释掉终端操作,可以发现结果不会被打印(这是因为Stream的懒加载,即没有终端操作的Stream将不会被真正运行)。

takeWhile & dropWhile

takeWhile定义:如果当前Stream流有序,则返回一个流,该流包含从此流中获取的与给定Predictae匹配的现有元素集。 如果当前Stream流无序,则返回由从此流中获取的与给定谓词匹配的元素子集组成的流。

Returns, if this stream is ordered, a stream consisting of the longest prefix of elements taken from this stream that match the given predicate. Otherwise returns, if this stream is unordered, a stream consisting of a subset of elements taken from this stream that match the given predicate.

dropWhile定义:如果当前Stream流有序,则返回在删除与给定Predicate匹配的元素的现有元素集之后由该流的其余元素组成的流。 如果当前Stream流无序,则返回在删除与给定谓词匹配的元素子集之后由该流的其余元素组成的流。

Returns, if this stream is ordered, a stream consisting of the remaining elements of this stream after dropping the longest prefix of elements that match the given predicate. Otherwise returns, if this stream is unordered, a stream consisting of the remaining elements of this stream after dropping a subset of elements that match the given predicate

理解:按顺序判断元素流是否符合给定的Predicate,当遇到第一个与给定Predicate不匹配的时候,takeWhile返回当前元素之前的所有元素(即不包含此判断失败的元素),dropWhile返回takeWhile的补集(即此判断失败的元素将被包含在dropWhile中)。如果元素流无序,则takeWhile相当于filter,dropWhile相当于filter补集。

Stream.of(10,2,9,4,5,0,18).takeWhile(s->s>1)                   //10,2,9,4,5.forEach(System.out::println);Stream.of(10,2,9,4,5,0,18).dropWhile(s->s>5)                   //2,9,4,5,0,18.forEach(System.out::println);

map, flatMap & mapMulti

map定义:返回一个包含当前元素映射结果的Stream流。

Returns a stream consisting of the results of applying the given function to the elements of this stream.

Stream.of(10,2,9,4,5,0,18).map(s -> s-1)                      //9,1,8,3,4,-1,17.forEach(System.out::println);

flatMap与map的区别

map会保留原先Stream的特定结构,而flatMap会扁平化原先的Stream流。

举例来说,现有两小箱钢管,map和flatMap做完处理后,map会返回两个小箱子(箱内装有处理后的钢管),flatMap会返回一个新的大箱子(箱内装有全部的处理后的钢管)。

如果还不理解,可看这里(一眼看穿flatMap和map的区别)。

mapMulti与map的区别

map的映射关系是一对一,即读取一个数据,处理完后,返回一个新数据。

mapMulti的映射关系是一对多,即读取一个数据,处理完后,可以返回多个新数据。

具体可见(Java 16 新方法 Stream.mapMult)。


四、终端操作 (Terminal Operation)

min & max

输入为Comparator,返回Optional。

Stream.of(4,2,1,5).max(Integer::compareTo).get();    //5
Stream.of(4,2,1,5).min(Integer::compareTo).get();    //1

count

无输入,返回Long。

Stream.of(4,2,1,5).count();                      //4

toArray

输入IntFunction(可选),返回数组。(这里的这个IntFunction主要是用来创建返回的数组以及分区执行或调整大小可能需要的任何其他数组的,用人话说就是保证返回类型不冲突的。)

Integer[] a = Stream.of(1,2,3,4,5,6,7,8,9).toArray(Integer[]::new);

noneMatch, allMatch & anyMatch

输入Predicate,返回boolean。

Stream.of("one", "two", "three", "four").noneMatch(s->s.equals("one"));    //falseStream.of("one", "two", "three", "four").allMatch(s->s.equals("one"));     //falseStream.of("one", "two", "three", "four").anyMatch(s->s.equals("one"));     //true

findAny & findFirst

无输入,返回Optional。

Optional内含一些常用方法,如get()、orElse()等,也可以应用Stream的一些静态方法如map、filter、of 等,需要了解(Optional详解可看这里Java 8 Optional使用介绍)。

findAny定义:返回一个描述当前Stream中某些元素的Optional,如果当前Stream为empty,返回空Optional。

Returns an Optional describing some element of the stream, or an empty Optional if the stream is empty.

findFirst定义:返回一个描述当前Stream中首位元素的Optional,如果当前Stream为empty,返回空Optional(如果当前Stream没有特定顺序,返回随机元素)。

Returns an Optional describing the first element of this stream, or an empty Optional if the stream is empty. If the stream has no encounter order, then any element may be returned.

Stream.of("one", "two", "three", "four").findFirst().get();
Stream.of("one", "two", "three", "four").findAny().get();

forEach & forEachOrdered

输入一个consumer,无返回。

forEach与forEachOrdered的区别

forEachOrdered 强调顺序,无论是序列流还是并行流,都将严格遵循既定顺序。但由此引发的问题是,这可能会牺牲掉并行流的优势。

forEach 在序列流中将遵循顺序,但是在并行流中,将优先保证并行效率,不一定遵循既定顺序。

是否遵循顺序 序列流 并行流
forEach 一定 不一定
forEachOrdered 一定 一定
System.out.println("--------------序列流forEach------------");
Stream.of(1,2,3,4,5,6,7,8,9).sequential().forEach(System.out::println);System.out.println("--------------序列流forEachOrdered------------");
Stream.of(1,2,3,4,5,6,7,8,9).sequential().forEachOrdered(System.out::println);System.out.println("--------------并行流forEach------------");
Stream.of(1,2,3,4,5,6,7,8,9).parallel().forEach(System.out::println);System.out.println("--------------并行流forEachOrdered------------");
Stream.of(1,2,3,4,5,6,7,8,9).parallel().forEachOrdered(System.out::println);

运行结果:

collect

该方法主要有两个应用方向。

1. <R> R collect​(Supplier<R> supplier, BiConsumer<R,​? super T> accumulator, BiConsumer<R,​R> combiner)

supplier——最终结果容器。(可选)

accumulator——计算临时结果的过。

combiner——把临时结果导入最终容器。(可选)

Stream.of(1,2,3,4,5,6,7,8).reduce(Integer::sum);Stream.of(1,2,3,4,5,6,7,8).reduce(1, Integer::max);List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

2. <R,​A> R collect​(Collector<? super T,​A,​R> collector)

该方法主要与 java.util.stream.Collectors 配合使用,用途很广,Collectors包含的方法也很多,这里只作主要示例。

List<String> asList = Stream.of("one", "two", "three","four").collect(Collectors.toList());    Map<String, List<Person>> peopleByCity = personStream.collect(Collectors.groupingBy(Person::getCity));Map<String, Map<String, List<Person>>> peopleByStateAndCity = personStream.collect(Collectors.groupingBy(Person::getState, Collectors.groupingBy(Person::getCity)));Map<Year, Long> contractsPerYear = clients.stream().collect(Collectors.groupingBy(SummarizeClients::getContractYear, Collectors.counting()));

reduce

该方法是max min count的基础。这里只作简单的示例,如果想详细了解,可以看这里(JAVA8 Stream流之reduce()方法详解)。

Stream.of(1,2,3,4,5,6,7,8,9).reduce((x,y)->x+y).get();      //45
Stream.of(1,2,3,4,5,6,7,8,9).reduce(10,(x,y)-> x>y? x:y);   //10 因为我们定义了一个初始值10,该初始值大于当前Stream中所有元素

参考文章

Java 8 Optional使用介绍

Java8 Stream流的使用

一眼看穿flatMap和map的区别

【Java 8 新特性】Java Stream中forEachOrdered()和forEach()

Java 16 新方法 Stream.mapMult

Java8 Stream的副作用

JAVA8 Stream流之reduce()方法详解

Java 8 中的 Optional 的优点究竟在哪里?

Java:Stream三部曲(三):Stream流处理器相关推荐

  1. Java JDK8新特性Stream流

    1.Stream流 1. 流,支持处理数据处理操作的源生成的元素序列.流有两个重要特性:1流水线:很多流操作本身会返回一个流,这样多的操作就可以链接起来,形成一个大的流水线.2,内部迭代.流的迭代是在 ...

  2. Java:Stream三部曲(一):函数式接口的理解与常用示例(Runnable、Comparator、Callable、Consumer、Predicate、Supplier、Function)

    目录 摘要 一.函数式接口(Functional Interface) 定义 附注 示例 二.JDK中常用的函数式接口 概览 1. Runnable 2. Comparator 用途:一个比较顺序的方 ...

  3. java(九)-方法引用, Stream流,File类 , 递归 ,字节流

    day09[方法引用.Lambda表达式.Stream流] 今日目标 线程状态 等待与唤醒 Lambda表达式 Stream流 教学目标 能够说出线程6个状态的名称 能够理解等待唤醒案例 能够掌握La ...

  4. java 两个stream合并_Java Stream 流如何进行合并操作

    1. 前言 Java Stream Api 提供了很多有用的 Api 让我们很方便将集合或者多个同类型的元素转换为流进行操作.今天我们来看看如何合并 Stream 流. 2. Stream 流的合并 ...

  5. java 合并流_Java Stream 流实现合并操作示例

    本文实例讲述了Java Stream 流实现合并操作.分享给大家供大家参考,具体如下: 1. 前言 Java Stream Api提供了很多有用的 Api 让我们很方便将集合或者多个同类型的元素转换为 ...

  6. java 新特性之 stream 流

    java 新特性之 stream 流 Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据. 这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在 ...

  7. Java函数式编程学习——Stream流

    目录 概述 案例数据准备 1. 常用操作 2. 中间操作 filter map distinct sorted limit skip flatMap 3. 终结操作 foreach count max ...

  8. java 8 stream入门_java8 Stream 流快速入门

    Stream 流 简介 Java 8 中,得益于 lambda 带来的函数式编程,引入了一个全新的 Stream流 概念,用于解决集合已有的弊端. 好处 我们先来看一个例子: 筛选出 names 中以 ...

  9. java 合并流_Java Stream 流如何进行合并操作

    1. 前言 Java Stream Api 提供了很多有用的 Api 让我们很方便将集合或者多个同类型的元素转换为流进行操作.今天我们来看看如何合并 Stream 流. 2. Stream 流的合并 ...

  10. CUDA流多处理器(stream multiprocessor,sm)和硬件流处理器(stream processor,sp)

    SM是一种单指令多线程((single Instruction MultipleThread,SIMT)架构的处理器,类似单指令流多数据流(SIMD)的特点,含有指令发射单元,及若干个流处理器(str ...

最新文章

  1. 架构思维:系统容量设计
  2. 利用位运算和指针实现的交换两个数的程序
  3. 你会么?图形不正,角度是随机的
  4. 谈谈阿里所谓的“要性”
  5. JAVA NIO知识点总结(2)——直接缓冲区和非直接缓冲区
  6. 择天记手游的服务器维护世界,3月8日停服更新公告
  7. 字符串hash(一)
  8. Basic4android v3.50 发布
  9. android for vs (三)visual studio android 发布为 apk
  10. NLP之路-python爬虫
  11. Android自定义类似ProgressDialog效果的Dialog
  12. 2018上海大学生网络安全赛 misc 92 wp
  13. 出售 Mac 时做好哪些准备?
  14. Linux系统维护人员的必备参考书
  15. MySQL将一张表的某些列数据,复制到另外一张表,并且修改某些内容
  16. Hibernate中的HQL语言
  17. ami码编码算法c语言,AMI码编码规则是什么
  18. 如何绘制逻辑图 — 8.逻辑的表达:数据逻辑
  19. U8字符串(u8前缀)的作用
  20. 如何做好一个产品经理-版本1.0

热门文章

  1. android手机管理器在哪里打开,安卓手机re管理器在哪里打开图文教程
  2. 如何使用分布式管理工具:Git
  3. 健康体检管理系统源码 运营级PEIS系统源码 PEIS健康体检系统源码 PEIS源码 B/S架构开发
  4. Graph U-Nets 笔记
  5. 计算机桌面变窄,电脑桌面图标变小怎么调整
  6. 朴素贝叶斯详解及其python实现
  7. python怎么学比较快,怎样快速学会python
  8. 南京周边城市两日游方案
  9. CryEngine5 Shader调试
  10. Windows Home Server V2 Code Name Vail Preview