测试环境

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.1.RELEASE</version><relativePath/> <!-- lookup parent from repository -->
</parent><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions>
</dependency>
import java.io.IOException;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;import org.junit.jupiter.api.Test;/*** @author yao liming* @since 2020/8/11 22:54*/
public class StreamTest {/*** 1、传入可变长度数组调用静态方法创建stream*/@Testvoid StreamOf() {// 没实质性用途,可做测试用Stream<String> stream = Stream.of("A", "B", "C", "D");stream.forEach(System.out::println);// 一个 Stream 只可以使用一次,下面的语句会报错// java.lang.IllegalStateException: stream has already been operated upon or closedstream.forEach(a -> System.out.println(a));}/*** 2、基于数组或集合创建stream*/@Testvoid basedOnArray() {Stream<String> stream1 = Arrays.stream(new String[] {"A", "B", "C", "D"});List<String> list = new ArrayList<>();list.add("X");list.add("Y");Stream<String> stream2 = list.stream();stream1.forEach(System.out::println);stream2.forEach(System.out::println);}/*** 基于Supplier创建的Stream会不断调用Supplier.get()方法来不断产生下一个元素,* 这种Stream保存的不是元素,而是算法,它可以用来表示无限序列。** 对于无限序列,如果直接调用forEach()或者count()这些最终求值操作,会进入死循环,* 因为永远无法计算完这个序列,所以正确的方法是先把无限序列变成有限序列*/@Testvoid generate() {Stream<Integer> natual = Stream.generate(new NatualSupplier());// 注意:无限序列必须先变成有限序列再打印:natual.limit(7).forEach(System.out::println);}class NatualSupplier implements Supplier<Integer> {int n = 0;@Overridepublic Integer get() {return ++n;}}@Testvoid testAnother() {// Files类的lines()方法可以把一个文件变成一个Stream,每个元素代表文件的一行内容try {Stream<String> lines = Files.lines(Paths.get("/data/test.txt"));} catch (IOException e) {e.printStackTrace();}// 正则表达式的Pattern对象有一个splitAsStream()方法,可以直接把一个长字符串分割成Stream序列而不是数组Pattern p = Pattern.compile("\\s+");Stream<String> s = p.splitAsStream("The quick brown fox jumps over the lazy dog");s.forEach(System.out::println);}@Testvoid basicDataTypes() {// 因为Java的范型不支持基本类型,所以我们无法用Stream<int>这样的类型,会发生编译错误。// 为了保存int,只能使用Stream<Integer>,但这样会产生频繁的装箱、拆箱操作。为了提高效率,// Java标准库提供了IntStream、LongStream和DoubleStream这三种使用基本类型的Stream,// 它们的使用方法和范型Stream没有大的区别,设计这三个Stream的目的是提高运行效率:IntStream is = Arrays.stream(new int[] {1, 2});LongStream longStream = Arrays.stream(new String[] {"3", "4"}).mapToLong(Long::parseLong);}@Testvoid Map() {// Stream.map()是Stream最常用的一个转换方法,它把一个Stream转换为另一个Stream// 利用map(),不但能完成数学计算,对于字符串操作,以及任何Java对象都是非常有用的List<String> list = Arrays.asList("  Apple ", " pear ", " ORANGE", " BaNaNa ");/*** 将T类型转换为R类型* @FunctionalInterface* public interface Function<T, R> {*     // 将T类型转换为R:*     R apply(T t);* }*/list.stream().map(String::trim).map(String::toLowerCase).forEach(System.out::println);}@Testvoid filter() {// 所谓filter()操作,就是对一个Stream的所有元素一一进行测试,// 不满足条件的就被“滤掉”了,剩下的满足条件的元素就构成了一个新的Stream/*** filter()方法接收的对象是Predicate接口对象,它定义了一个test()方法,负责判断元素是否符合条件* @FunctionalInterface* public interface Predicate<T> {*     // 判断元素t是否符合条件:*     boolean test(T t);* }*/// 过滤掉偶数,保留奇数集合IntStream.of(1, 2, 3, 4, 5).filter(number -> number % 2 != 0).forEach(System.out::println);}@Testvoid streamFilterGenerate() {Stream.generate(new LocalDateSupplier()).limit(31).filter(ldt -> {return ldt.getDayOfWeek() == DayOfWeek.SATURDAY || ldt.getDayOfWeek() == DayOfWeek.SUNDAY;}).forEach(System.out::println);}class LocalDateSupplier implements Supplier<LocalDate>{LocalDate start = LocalDate.of(2020,8,1);int n= -1;@Overridepublic LocalDate get() {n++;return start.plusDays(n);}}@Testvoid reduce(){Integer sum = Stream.of(1, 2, 3, 4, 5, 6).reduce(0, (acc, n) -> acc + n);System.out.println(sum);/*** @FunctionalInterface* public interface BinaryOperator<T> {*     // Bi操作:两个输入,一个输出*     T apply(T t, T u);* }*///上述代码看上去不好理解,但我们用for循环改写一下,就容易理解了:/*** Stream<Integer> stream = ...*         int sum = 0;*         for (n : stream) {*             sum = (sum, n) -> sum + n;*         }*/// 可见,reduce()操作首先初始化结果为指定值(这里是0),紧接着,// reduce()对每个元素依次调用(acc, n) -> acc + n,其中,acc是上次计算的结果:/*** // 计算过程:* acc = 0 // 初始化为指定值* acc = acc + n = 0 + 1 = 1 // n = 1* acc = acc + n = 1 + 2 = 3 // n = 2* acc = acc + n = 3 + 3 = 6 // n = 3* acc = acc + n = 6 + 4 = 10 // n = 4* acc = acc + n = 10 + 5 = 15 // n = 5* acc = acc + n = 15 + 6 = 21 // n = 6*/// 因此,实际上这个reduce()操作是一个求和。//如果去掉初始值,我们会得到一个Optional<Integer>Optional<Integer> opt = Stream.of(1, 2, 3, 4, 5, 6).reduce((acc, n) -> acc + n);System.out.println(Optional.ofNullable(opt.get()).orElse(1));//把求和改为乘积,但是必须注意初始乘数必须为1Integer product = Stream.of(1, 2, 3, 4, 5, 6).reduce(1, (acc, n) -> acc * n);System.out.println(product);}/*** 对Stream来说可以分为两类,* 一类是转换操作,即把一个Stream转换为另一个Stream,例如map()和filter(),* 另一类是聚合操作,即对Stream的每个元素进行计算,得到一个确定的结果,例如reduce()*/@Testvoid toList() {/*** 把Stream的每个元素收集到List的方法是调用collect()并传入Collectors.toList()对象,* 它实际上是一个Collector实例,通过类似reduce()的操作,把每个元素添加到一个收集器中(实际上是ArrayList)。** 类似的,collect(Collectors.toSet())可以把Stream的每个元素收集到Set中。*/List<String> list = Stream.of("Apple", "", null, "Pear", "  ", "Orange").filter(str -> Objects.nonNull(str) && !str.isEmpty()).collect(Collectors.toList());// [Apple, Pear, , Orange]System.out.println(list);}@Testvoid toArray(){/*** 注意到传入的“构造方法”是String[]::new,* 它的签名实际上是IntFunction<String[]>定义的String[] apply(int),即传入int参数,获得String[]数组的返回值。*/String[] array = Stream.of("Apple", "", null, "Pear", "  ", "Orange").toArray(String[]::new);}@Testvoid toMap(){Map<String, String> map = Stream.of("APPL:Apple", "MSFT:Microsoft").collect(Collectors.toMap(s -> s.substring(0, s.indexOf(":")), s -> s.substring(s.indexOf(":") + 1)));System.out.println(map);}/*** 分组输出使用Collectors.groupingBy(),它需要提供两个函数:* 一个是分组的key,这里使用s -> s.substring(0, 1),表示只要首字母相同的String分到一组,* 第二个是分组的value,这里直接使用Collectors.toList(),表示输出为List*/@Testvoid groupingBy(){Map<String, List<String>> collect =Stream.of("Apple", "Banana", "Blackberry", "Coconut", "Avocado", "Cherry", "Apricots").collect(Collectors.groupingBy(s -> s.substring(0, 1), Collectors.toList()));//{A=[Apple, Avocado, Apricots], B=[Banana, Blackberry], C=[Coconut, Cherry]}System.out.println(collect);}@Testvoid sorted() {// [Banana, Orange, apple]// 此方法要求Stream的每个元素必须实现Comparable接口。如果要自定义排序,传入指定的ComparatorSystem.out.println(Stream.of("Orange", "apple", "Banana").sorted().collect(Collectors.toList()));// [apple, Banana, Orange]System.out.println(Stream.of("Orange", "apple", "Banana").sorted(String::compareToIgnoreCase).collect(Collectors.toList()));System.out.println(Stream.of("Orange", "apple", "Banana").sorted(String::compareToIgnoreCase).collect(Collectors.toList()));}@Testvoid distinct() {// [A, B, C, D]System.out.println(Stream.of("A", "B", "A", "C", "B", "D").distinct().collect(Collectors.toList()));}@Testvoid Intercept() {// 截取操作常用于把一个无限的Stream转换成有限的Stream,// skip()用于跳过当前Stream的前N个元素,limit()用于截取当前Stream最多前N个元素// [C, D, E]System.out.println(Stream.of("A", "B", "C", "D", "E", "F").skip(2).limit(3).collect(Collectors.toList()));// [C]System.out.println(Stream.of("A", "B", "C", "D", "E", "F").limit(3).skip(2).collect(Collectors.toList()));}/*** 将两个Stream合并为一个Stream可以使用Stream的静态方法concat()*/@Testvoid concat(){Stream<String> a = Stream.of("A", "B", "C");Stream<Integer> b = Stream.of(1, 2);Stream<? extends Serializable> concat = Stream.concat(a, b);System.out.println(concat.collect(Collectors.toList()));}@Testvoid flatMap(){//所谓flatMap(),是指把Stream的每个元素(这里是List)映射为Stream,然后合并成一个新的StreamStream<Integer> integerStream =Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4), Arrays.asList(5, 6, 7)).flatMap(list -> list.stream());System.out.println(integerStream.collect(Collectors.toList()));}/*** 通常情况下,对Stream的元素进行处理是单线程的,即一个一个元素进行处理。* 但是很多时候,我们希望可以并行处理Stream的元素,因为在元素数量非常大的情况,并行处理可以大大加快处理速度。** 把一个普通Stream转换为可以并行处理的Stream非常简单,只需要用parallel()进行转换** 经过parallel()转换后的Stream只要可能,就会对后续操作进行并行处理。* 我们不需要编写任何多线程代码就可以享受到并行处理带来的执行效率的提升*/@Testvoid parallel(){Stream<String> s = Stream.of("a","b");String[] result = s.parallel() // 变成一个可以并行处理的Stream.sorted() // 可以进行并行排序.toArray(String[]::new);}
}

其他聚合方法

除了reduce()和collect()外,Stream还有一些常用的聚合方法:count():用于返回元素个数;
max(Comparator<? super T> cp):找出最大元素;
min(Comparator<? super T> cp):找出最小元素。
针对IntStream、LongStream和DoubleStream,还额外提供了以下聚合方法:sum():对所有元素求和;
average():对所有元素求平均数。
还有一些方法,用来测试Stream的元素是否满足以下条件:boolean allMatch(Predicate<? super T>):测试是否所有元素均满足测试条件;
boolean anyMatch(Predicate<? super T>):测试是否至少有一个元素满足测试条件。
最后一个常用的方法是forEach()

小结

Stream提供的常用操作有:

  • 转换操作:map(),filter(),sorted(),distinct();
  • 合并操作:concat(),flatMap();
  • 并行处理:parallel();
  • 聚合操作:reduce(),collect(),count(),max(),min(),sum(),average();
  • 其他操作:allMatch(), anyMatch(), forEach()。

资料参考

  • 使用Stream

java.util.stream.Stream案例解读相关推荐

  1. java.util.stream.Stream

    https://blog.csdn.net/qq_40794973/article/details/86882454#t32 2 案例数据来源 @Data public class Employee ...

  2. java中的Stream

    1. Stream流 1.1. Stream流引入 Stream流完全不是I/O流,按照流水线处理方式来考虑代码中的思想. JDK1.8 之后,我们拥有了Lambda表达式,让代码的中心偏向解决实际问 ...

  3. 【Java】流(Stream)快速入门

    本文是面向Java初学者的流(Stream)学习指导教程.文章内容偏向怎么用,而弱化其诞生背景.流的概念.内部原理等说明解释性的语段. 主要内容: Optional 创建流 操作流 收集流 目录 什么 ...

  4. 从Java 8中的java.util.stream.Stream检索列表

    本文翻译自:Retrieving a List from a java.util.stream.Stream in Java 8 I was playing around with Java 8 la ...

  5. Java Streams,第 1 部分: java.util.stream 库简介

    Java SE 8 中主要的新语言特性是拉姆达表达式.可以将拉姆达表达式想作一种匿名方法:像方法一样,拉姆达 表达式具有带类型的参数.主体和返回类型.但真正的亮点不是拉姆达表达式本身,而是它们所实现的 ...

  6. java.util.stream_java.util.stream.Stream 接口中的常用方法

    流模型的操作很丰富,下面介绍一些常用的API.这些方法可以被分成两种: 延迟方法 返回值类型仍然是 Stream 接口自身类型的方法,因此支持链式调用.(除了终结方法外,其余方 法均为延迟方法.) 终 ...

  7. java util包排序,利用stream sorted进行降序排序

    根据value值的大小进行降序排序,并进行截取. public static void main(String[] args) { List> list = Lists.newArrayList ...

  8. java.util.stream.Stream详解

    Stream(流)是一个支持顺序和平行聚合操作的元素序列,和java.util.List类似,是jdk1.8的新特性.可以看出Stream还有几个兄弟类IntStream.LongStream和Dou ...

  9. 【苹果iMessage推送家庭推】苹果位置推导入Java入口java.util.stream.collectors; tmpmaclist

    推荐内容IMESSGAE相关 作者✈️@IMEAE推荐内容 iMessage苹果推软件 *** 点击即可查看作者要求内容信息 作者✈️@IMEAE推荐内容 1.家庭推内容 *** 点击即可查看作者要求 ...

最新文章

  1. poj3264(ST表模版)
  2. 浮动元素的display属性
  3. discuz云平台报调用远程接口失败的问题分析和解决
  4. CentOS 7.1下KVM的安装与配置
  5. JavaScript--我所理解的原型链
  6. 字符串存入xls matlab,数组 – MATLAB:将字符串写入Excel
  7. EXCEL中如何撤销工作表保护
  8. EXPLORING BALANCED FEATURE SPACES FOR REP-RESENTATION LEARNING(2022.5.18)
  9. mongodb删除某个字段
  10. WPF无边框窗体拖动
  11. 太原理工大学系统分析与设计实验报告实验室设备_“艺术之光”绽放太原理工大学首届本科生专业节...
  12. zip格式压缩文件并打包下载
  13. Fiddler4 手机抓包
  14. 中国香茅醇行业研究与投资预测报告(2022版)
  15. wifi打印机打印(二维码,条形码等)
  16. 华为腾讯汉能:叫响世界的三大中国自主创新企业
  17. 《Mysql是怎样运行的》读书笔记之B+树索引的使用
  18. centos单机部署greenplum
  19. windows7显示摄像头图标 ECap
  20. 小黑记事本怎样设置html,小黑记事本如何使用便签?便签使用方法大放送

热门文章

  1. Xilinx官网大全__PowerPC 架构
  2. 深度学习服务器,配置推荐来啦?
  3. python 之 第一次亲密接触
  4. 计算机专业毕业祝福语,祝考试成功的60句祝福语
  5. 淘客漏洞群用的什么机器人_淘客返利机器人常见封号原因及解决办法
  6. 用 Electron 打造 Win/Mac 应用,从「代码」到可下载的「安装包」,可能比你想得麻烦一点... 1
  7. 用imspost制作catia后处理_基于IMS POST五轴海德汉系统后处理的开发
  8. 【每日新闻】欧盟委员会对华硕等4家公司处以1.3亿美元罚款;谷歌发布多款AI工具:帮大众更好地利用人工智能...
  9. 魔鬼交易员害了法兴银行却救了全球经济?
  10. conda删除虚拟环境