一、Java Stream管道数据处理操作

在本号之前写过的文章中,曾经给大家介绍过 Java Stream管道流是用于简化集合类元素处理的java API。在使用的过程中分为三个阶段。在开始本文之前,我觉得仍然需要给一些新朋友介绍一下这三个阶段,如图:

  • 第一阶段(图中蓝色):将集合、数组、或行文本文件转换为java Stream管道流
  • 第二阶段(图中虚线部分):管道流式数据处理操作,处理管道中的每一个元素。上一个管道中的输出元素作为下一个管道的输入元素。
  • 第三阶段(图中绿色):管道流结果处理操作,也就是本文的将介绍的核心内容。

在开始学习之前,仍然有必要回顾一下我们之前给大家讲过的一个例子:


List<String> nameStrs = Arrays.asList("Monkey", "Lion", "Giraffe","Lemur"); List<String> list = nameStrs.stream()
.filter(s -> s.startsWith("L"))
.map(String::toUpperCase)
.sorted()
.collect(toList());
System.out.println(list);
  • 首先使用stream()方法将字符串List转换为管道流Stream
  • 然后进行管道数据处理操作,先用fliter函数过滤所有大写L开头的字符串,然后将管道中的字符串转换为大写字母toUpperCase,然后调用sorted方法排序。这些API的用法在本号之前的文章有介绍过。其中还使用到了lambda表达式和函数引用。
  • 最后使用collect函数进行结果处理,将java Stream管道流转换为List。最终list的输出结果是:[LEMUR, LION]

如果你不使用java Stream管道流的话,想一想你需要多少行代码完成上面的功能呢?回到正题,这篇文章就是要给大家介绍第三阶段:对管道流处理结果都可以做哪些操作呢?下面开始吧!

二、ForEach和ForEachOrdered

如果我们只是希望将Stream管道流的处理结果打印出来,而不是进行类型转换,我们就可以使用forEach()方法或forEachOrdered()方法。


Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
.parallel()
.forEach(System.out::println);
Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
.parallel()
.forEachOrdered(System.out::println);
  • parallel()函数表示对管道中的元素进行并行处理,而不是串行处理,这样处理速度更快。但是这样就有可能导致管道流中后面的元素先处理,前面的元素后处理,也就是元素的顺序无法保证
  • forEachOrdered从名字上看就可以理解,虽然在数据处理顺序上可能无法保障,但是forEachOrdered方法可以在元素输出的顺序上保证与元素进入管道流的顺序一致。也就是下面的样子(forEach方法则无法保证这个顺序):
Monkey
Lion
Giraffe
Lemur
Lion

三、元素的收集collect

java Stream 最常见的用法就是:一将集合类转换成管道流,二对管道流数据处理,三将管道流处理结果在转换成集合类。那么collect()方法就为我们提供了这样的功能:将管道流处理结果在转换成集合类。

3.1.收集为Set

通过Collectors.toSet()方法收集Stream的处理结果,将所有元素收集到Set集合中。


Set<String> collectToSet = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
)
.collect(Collectors.toSet()); //最终collectToSet 中的元素是:[Monkey, Lion, Giraffe, Lemur],注意Set会去重。

3.2.收集到List

同样,可以将元素收集到List使用toList()收集器中。


List<String> collectToList = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
).collect(Collectors.toList()); // 最终collectToList中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]

3.3.通用的收集方式

上面为大家介绍的元素收集方式,都是专用的。比如使用Collectors.toSet()收集为Set类型集合;使用Collectors.toList()收集为List类型集合。那么,有没有一种比较通用的数据元素收集方式,将数据收集为任意的Collection接口子类型。

所以,这里就像大家介绍一种通用的元素收集方式,你可以将数据元素收集到任意的Collection类型:即向所需Collection类型提供构造函数的方式。


LinkedList<String> collectToCollection = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
).collect(Collectors.toCollection(LinkedList::new)); //最终collectToCollection中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]

注意:代码中使用了LinkedList::new,实际是调用LinkedList的构造函数,将元素收集到Linked List。当然你还可以使用诸如LinkedHashSet::newPriorityQueue::new将数据元素收集为其他的集合类型,这样就比较通用了。

3.4.收集到Array

通过toArray(String[]::new)方法收集Stream的处理结果,将所有元素收集到字符串数组中。


String[] toArray = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
) .toArray(String[]::new); //最终toArray字符串数组中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]

3.5.收集到Map

使用Collectors.toMap()方法将数据元素收集到Map里面,但是出现一个问题:那就是管道中的元素是作为key,还是作为value。我们用到了一个Function.identity()方法,该方法很简单就是返回一个“ t -> t ”(输入就是输出的lambda表达式)。另外使用管道流处理函数distinct()来确保Map键值的唯一性。


Map<String, Integer> toMap = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
)
.distinct()
.collect(Collectors.toMap(
Function.identity(), //元素输入就是输出,作为key
s -> (int) s.chars().distinct().count()// 输入元素的不同的字母个数,作为value
)); // 最终toMap的结果是: {Monkey=6, Lion=4, Lemur=5, Giraffe=6}

3.6.分组收集groupingBy

Collectors.groupingBy用来实现元素的分组收集,下面的代码演示如何根据首字母将不同的数据元素收集到不同的List,并封装为Map。


Map<Character, List<String>> groupingByList = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
)
.collect(Collectors.groupingBy(
s -> s.charAt(0) , //根据元素首字母分组,相同的在一组
// counting() // 加上这一行代码可以实现分组统计
)); // 最终groupingByList内的元素: {G=[Giraffe], L=[Lion, Lemur, Lion], M=[Monkey]}
//如果加上counting() ,结果是: {G=1, L=3, M=1}

四、其他常用方法


boolean containsTwo = IntStream.of(1, 2, 3).anyMatch(i -> i == 2);
// 判断管道中是否包含2,结果是: true long nrOfAnimals = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur"
).count();
// 管道中元素数据总计结果nrOfAnimals: 4 int sum = IntStream.of(1, 2, 3).sum();
// 管道中元素数据累加结果sum: 6 OptionalDouble average = IntStream.of(1, 2, 3).average();
//管道中元素数据平均值average: OptionalDouble[2.0] int max = IntStream.of(1, 2, 3).max().orElse(0);
//管道中元素数据最大值max: 3 IntSummaryStatistics statistics = IntStream.of(1, 2, 3).summaryStatistics();
// 全面的统计结果statistics: IntSummaryStatistics{count=3, sum=6, min=1, average=2.000000, max=3}

期待您的关注

Java Stream函数式编程第三篇:管道流结果处理的更多相关文章

  1. Java Stream函数式编程图文详解(二):管道数据处理

    一.Java Stream管道数据处理操作 在本号之前发布的文章<Java Stream函数式编程?用过都说好,案例图文详解送给你>中,笔者对Java Stream的介绍以及简单的使用方法 ...

  2. Java Stream函数式编程案例图文详解

    导读 作者计划把Java Stream写成一个系列的文章,本文只是其中一节.更多内容期待您关注我的号! 一.什么是Java Stream? Java Stream函数式编程接口最初是在Java 8中引 ...

  3. Java 8 函数式编程

    今天打开Oracle Java官网一看,Java已经更新到 13 了 https://www.oracle.com/technetwork/java/javase/jdk-relnotes-index ...

  4. [ 高并发]Java高并发编程系列第二篇--线程同步

    高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...

  5. 转:JavaScript函数式编程(三)

    转:JavaScript函数式编程(三) 作者: Stark伟 这是完结篇了. 在第二篇文章里,我们介绍了 Maybe.Either.IO 等几种常见的 Functor,或许很多看完第二篇文章的人都会 ...

  6. paip. java的 函数式编程 大法

    paip. java的 函数式编程 大法 Java 语言中常被忽视的一个方面是它被归类为一种命令式(imperative)编程语言.命令式编程虽然由于与 Java 语言的关联而相当普及,但是并不是惟一 ...

  7. Java函数式编程:三、流与函数式编程

    本文是Java函数式编程的最后一篇,承接上文: Java函数式编程:一.函数式接口,lambda表达式和方法引用 Java函数式编程:二.高阶函数,闭包,函数组合以及柯里化 前面都是概念和铺垫,主要讲 ...

  8. Java中的函数式编程(三)lambda表达式

    写在前面 lambda表达式是一个匿名函数.在Java 8中,它和函数式接口一起,共同构建了函数式编程的框架.   lambda表达式乍看像是匿名内部类的一种语法糖,但实际上,它们是两种本质不同的事物 ...

  9. 快速掌握Java8 Stream函数式编程技巧

    函数式编程优势 "函数第一位",即函数可以出现在任何地方. 可以把函数作为参数传递给另一个函数,还可以将函数作为返回值. 让代码的逻辑更清晰更优雅. 减少了可变量(Immutabl ...

随机推荐

  1. .NetCore WebApi —— Swagger版本控制

    目录: .NetCore WebApi——Swagger简单配置 .NetCore WebApi——基于JWT的简单身份认证与授权(Swagger) .NetCore WebApi —— Swagge ...

  2. python程序调用C/C++代码

    这篇用来记录在些模拟Canoe生成CAN数据桢工具时遇到的问题, 生成CAN数据桢,主要分为两个关注点: 1.如何从can信号名获取到can信号的ID长度以及信号的起始位,并将信号值按照一定的规则填写 ...

  3. Uber Go 语言编程规范

    目录 Uber Go 语言编程规范 1. 介绍 2. 编程指南 3. 性能相关 4. 编程风格 5. 编程模式(Patterns) 6. 总结 Uber Go 语言编程规范 相信很多人前两天都看到 U ...

  4. Z-buffer算法

    1.Z缓冲区(Z-Buffer)算法 1973年,犹他大学学生艾德·卡姆尔(Edwin Catmull)独 立开发出了能跟踪屏幕上每个像素深度的算法 Z-buffer Z-buffer让计算机生成复杂 ...

  5. vue事件获取当前对象

    一.事件传参 如点击事件 <div @click='click'> <div> <div @click='click_1('msg')'> <div> ...

  6. C、C++的Makefile模板

    目录 Makefile模板 用法 编译C程序 编译C++程序 其他 Tips Makefile模板 CC = gcc LD = $(CC) TARGET = $(notdir $(CURDIR)) S ...

  7. [NOIp2014] luogu P2312 解方程

    题目描述 已知方程∑i=0naixi=0\sum_{i=0}^{n}{a_ix^i}=0i=0∑n​ai​xi=0求该方程在 [1,m][1,m][1,m] 内的整数解. Solution 有一个秦九 ...

  8. [NOIp2018] luogu P5021 赛道修建

    我同学的歌 题目描述 你有一棵树,每条边都有权值 did_idi​.现在要修建 mmm 条赛道,一条赛道是一条连贯的链,且一条边至多出现在一条赛道里.一条赛道的长被定义为,组成这条赛道的边的权值之和. ...

  9. [HNOI2007] 理想正方形 二维ST表

    题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一行为3个整数,分别表示a,b,n的值 第二行至 ...

  10. 关于vue使用的一些小经验

    这一年来说,vue的势头很猛,用户量“噌”“噌”“噌”的涨 为了不掉队不落伍.在后台大哥的胁迫下,不得不选择用了它 刚开始很难接受vue的写法,在编辑器里很容易报错,基本上每行都会出现红色的波浪线 这 ...