Stream编程之Collectors.joining方法解析
首先看一个例子
List<String> list = Lists.newArrayList("a", "b", "c", "a", "e", "f");
String result = list.stream().collect(Collectors.joining());
输出为 abcdef
简单快捷的实现List转字符串的拼接。对于初学者来说Stream类确实让人迷惑,虽然Java8发布了很久,相信很多人跟我一样,到目前为止我的编码风格还是Java6时期。很久前看es, IK分词器源码时看到了类似用法。最近时间充裕,所以特地补补Stream编程知识(不一定熟练用Stream,最起码能做到看到不陌生)。
Java8函数式编程资料下载
Collectors
本文主要讨论Collectors类。在list.stream()后得到了Stream对象,然后调用collect()得到结果。collect的行为是Collectors.joining。JDK封装了Collectors类,可以满足很多场景。常用方法有minBy(), maxBy(), toList(), toSet(), toMap()等等。先看看Collectors.joining的实现,
public static Collector<CharSequence, ?, String> joining() {return new CollectorImpl<CharSequence, StringBuilder, String>(StringBuilder::new, StringBuilder::append,(r1, r2) -> { r1.append(r2); return r1; },StringBuilder::toString, CH_NOID);
}
joining方法创建了一个CollectImpl实例,泛型CharSequence, StringBuilder, String。并传递了5个lambda表达式。
为了更清楚的了解joining方法,先看看CollectorImpl类的定义:
static class CollectorImpl<T, A, R> implements Collector<T, A, R><T> - the type of elements to be collected 要收集的元素类型
<A> - the mutable accumulation type of the reduction operation (often hidden as an implementation detail) reduction操作的可变 accumulate 类型
<R> - the type of the result 结果类型
CollectorImpl类的构造方法
CollectorImpl(Supplier<A> supplier,BiConsumer<A, T> accumulator,BinaryOperator<A> combiner,Function<A,R> finisher,Set<Characteristics> characteristics)
参数含义如下:
构造参数 | 描述 | 泛型 |
---|---|---|
Supplier supplier | 供应器 | A |
BiConsumer<A, T> accumulator | 累加器 | A, T |
BinaryOperator combiner | 组合器(并行时使用) | A |
Function<A,R> finisher | 结果转换器 | A, R |
Set<Characteristics> characteristics | 特征 | Characteristics |
为了更明确些,joining方法和CollectorImpl类的构造参数做对比,
joining | CollectorImpl构造参数 |
---|---|
StringBuilder::new | Supplier supplier |
StringBuilder::append | BiConsumer<A, T> accumulator |
(r1, r2) -> { r1.append(r2); return r1; } | BinaryOperator combiner |
StringBuilder::toString | Function<A,R> finisher |
Set characteristics | Set<Characteristics> characteristics |
如果对lambda熟悉的话,到这里足够清晰了,非并行的执行步骤如下:
- 调用supplier得到A,即StringBuffer对象。
- 循环调用accumulator,传递参数A,T。即StringBuffer对象和list中的每个元素。行为是append()。
- 调用finisher转换结果,从A得到R,即StringBuffer的toString方法。
还原成java传统风格
下面把lambda代码还原成Java6的风格
List<String> list = Lists.newArrayList("a", "b", "c", "a", "e", "f");
final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
String result = list.stream().collect(new Collector<CharSequence, StringBuilder, String>() {@Overridepublic Supplier<StringBuilder> supplier() {return new Supplier<StringBuilder>() {@Overridepublic StringBuilder get() {System.out.println(Thread.currentThread().getName() + " supplier");return new StringBuilder();}};}@Overridepublic BiConsumer<StringBuilder, CharSequence> accumulator() {return new BiConsumer<StringBuilder, CharSequence>() {@Overridepublic void accept(StringBuilder stringBuilder, CharSequence charSequence) {System.out.println(Thread.currentThread().getName() + " accumulator, stringBuilder: " + stringBuilder + ", charSequence: " + charSequence);stringBuilder.append(charSequence);}};}@Overridepublic BinaryOperator<StringBuilder> combiner() {return new BinaryOperator<StringBuilder>() {@Overridepublic StringBuilder apply(StringBuilder stringBuilder, StringBuilder stringBuilder2) {System.out.println(Thread.currentThread().getName() + " combiner, s: " + stringBuilder.toString() + ", s2: " + stringBuilder2.toString());return stringBuilder.append(stringBuilder2);}};}@Overridepublic Function<StringBuilder, String> finisher() {return new Function<StringBuilder, String>() {@Overridepublic String apply(StringBuilder stringBuilder) {System.out.println(Thread.currentThread().getName() + " finisher: " + stringBuilder.toString());return stringBuilder.toString();}};}@Overridepublic Set<Characteristics> characteristics() {System.out.println(Thread.currentThread().getName() + " characteristics");return CH_NOID;}
});
运行结果和joining()方法一致。了解了joining的运行方式后,我们就能够自定义更复杂的collect和reduce了。
看到Java传统风格的代码是不是很亲切?有些人可能会说:“Java还是那个Java”。我更想说,对于Java8/9不熟悉的程序员,抓紧学习吧。
Java8函数式编程资料下载
Stream编程之Collectors.joining方法解析相关推荐
- Java 字符串拼接4种实现方法(for循环、stream().reduce()、Collectors.joining()、String.join())
1 for循环实现 List<String> list = new ArrayList<>(Arrays.asList("1", "2" ...
- Android 网络编程之OkHttp源码解析
前言:OkHttp框架是Android的网络请求框架,无数的项目都在使用着这个框架,重要性不言而喻; 本文会将OKHTTP的源码进行拆解,每个部分来单独学习,由简入深,循序渐进,篇幅较长,建议收藏,慢 ...
- Java并发编程之FutureTask源码解析
上次总结一下AQS的一些相关知识,这次总结了一下FutureTask的东西,相对于AQS来说简单好多呀 之前提到过一个LockSupport的工具类,也了解一下这个工具类的用法,这里也巩固一下吧 /* ...
- Java并发编程之CountDownLatch源码解析
一.导语 最近在学习并发编程原理,所以准备整理一下自己学到的知识,先写一篇CountDownLatch的源码分析,之后希望可以慢慢写完整个并发编程. 二.什么是CountDownLatch Count ...
- java并发编程之Thread.sleep方法详解
Thread.sleep方法的作用: 使当前线程暂停执行一段时间,交出cpu的执行时间片,并且在暂停期间不会参与cpu时间片的获取.直到等待时间结束恢复到就绪状态,是否执行还要看OS的调度,或者在这段 ...
- java并发编程之thread.join()方法详解
thread.join()方法的作用:保证线程的执行结果的可见性.原理是通过阻塞主线程实现的. 代码Demo如下: public class ThreadJoinDemo {public static ...
- Qt编程之QTreeWidget使用方法
ui->treeWidget->setColumnCount(1);ui->treeWidget->setHeaderLabel("中华人民共和国");QT ...
- linux网络编程之用select方法实现io复用(基于udp)
1.基本概念 IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程.IO多路复用适用如下场合: (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/ ...
- 【Stream流学习】Java 8 新特性|Collectors.joining() 案例详解
[辰兮要努力]:hello你好我是辰兮,很高兴你能来阅读,昵称是希望自己能不断精进,向着优秀程序员前行! 博客来源于项目以及编程中遇到的问题总结,偶尔会有读书分享,我会陆续更新Java前端.后台.数据 ...
最新文章
- 独家 | 5个机器学习开源项目来挑战你的数据科学技能!(附链接)
- Python OS 文件操作模块常用函数
- 三十九、@staticmethod、@classmethod和@property类装饰器
- Wpf控件ListBox使用实例2
- 奇门遁甲时家转盘奇门排盘,带八字排盘
- Dijkstra算法结合时间窗规划无冲突路径
- 生成式对抗网络(GAN)相关问题汇总(较全面)
- 可取回的国内csgo开箱网站incsgo开箱
- python模拟登录qq邮箱爬取_python模拟登录qq邮箱
- 使用pymysql报错RuntimeError ‘cryptography‘ package is required for sha256_password or caching_sha2_passw
- Win8初体验 内存/SSD硬盘性能挑Win7(一)
- android view.setVisibility 不显示问题
- 一周年感谢信 | 黑萤科技赖志宇:志同者将道合一处
- 【综合应用】基础PLS-SEM模型STATA实战
- vue 数组中嵌套数组_vue数组嵌套数组的问题
- 基于 Oauth 2.0 的第三方账号登录实现
- QT5.9.4 + cmake + VC2017 运行”run cmake“出现错误:xxx is not able to compile a simple test
- 2023湖北土建施工员证报考条件考试时间及报考流程 启程别
- 【蓝桥杯嵌入式】第十三届蓝桥杯嵌入式省赛客观题以及详细题解
- 保安也有梦之Java学习