首先看一个例子

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熟悉的话,到这里足够清晰了,非并行的执行步骤如下:

  1. 调用supplier得到A,即StringBuffer对象。
  2. 循环调用accumulator,传递参数A,T。即StringBuffer对象和list中的每个元素。行为是append()。
  3. 调用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方法解析相关推荐

  1. Java 字符串拼接4种实现方法(for循环、stream().reduce()、Collectors.joining()、String.join())

    1 for循环实现 List<String> list = new ArrayList<>(Arrays.asList("1", "2" ...

  2. Android 网络编程之OkHttp源码解析

    前言:OkHttp框架是Android的网络请求框架,无数的项目都在使用着这个框架,重要性不言而喻; 本文会将OKHTTP的源码进行拆解,每个部分来单独学习,由简入深,循序渐进,篇幅较长,建议收藏,慢 ...

  3. Java并发编程之FutureTask源码解析

    上次总结一下AQS的一些相关知识,这次总结了一下FutureTask的东西,相对于AQS来说简单好多呀 之前提到过一个LockSupport的工具类,也了解一下这个工具类的用法,这里也巩固一下吧 /* ...

  4. Java并发编程之CountDownLatch源码解析

    一.导语 最近在学习并发编程原理,所以准备整理一下自己学到的知识,先写一篇CountDownLatch的源码分析,之后希望可以慢慢写完整个并发编程. 二.什么是CountDownLatch Count ...

  5. java并发编程之Thread.sleep方法详解

    Thread.sleep方法的作用: 使当前线程暂停执行一段时间,交出cpu的执行时间片,并且在暂停期间不会参与cpu时间片的获取.直到等待时间结束恢复到就绪状态,是否执行还要看OS的调度,或者在这段 ...

  6. java并发编程之thread.join()方法详解

    thread.join()方法的作用:保证线程的执行结果的可见性.原理是通过阻塞主线程实现的. 代码Demo如下: public class ThreadJoinDemo {public static ...

  7. Qt编程之QTreeWidget使用方法

    ui->treeWidget->setColumnCount(1);ui->treeWidget->setHeaderLabel("中华人民共和国");QT ...

  8. linux网络编程之用select方法实现io复用(基于udp)

    1.基本概念 IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程.IO多路复用适用如下场合: (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/ ...

  9. 【Stream流学习】Java 8 新特性|Collectors.joining() 案例详解

    [辰兮要努力]:hello你好我是辰兮,很高兴你能来阅读,昵称是希望自己能不断精进,向着优秀程序员前行! 博客来源于项目以及编程中遇到的问题总结,偶尔会有读书分享,我会陆续更新Java前端.后台.数据 ...

最新文章

  1. 独家 | 5个机器学习开源项目来挑战你的数据科学技能!(附链接)
  2. Python OS 文件操作模块常用函数
  3. 三十九、@staticmethod、@classmethod和@property类装饰器
  4. Wpf控件ListBox使用实例2
  5. 奇门遁甲时家转盘奇门排盘,带八字排盘
  6. Dijkstra算法结合时间窗规划无冲突路径
  7. 生成式对抗网络(GAN)相关问题汇总(较全面)
  8. 可取回的国内csgo开箱网站incsgo开箱
  9. python模拟登录qq邮箱爬取_python模拟登录qq邮箱
  10. 使用pymysql报错RuntimeError ‘cryptography‘ package is required for sha256_password or caching_sha2_passw
  11. Win8初体验 内存/SSD硬盘性能挑Win7(一)
  12. android view.setVisibility 不显示问题
  13. 一周年感谢信 | 黑萤科技赖志宇:志同者将道合一处
  14. 【综合应用】基础PLS-SEM模型STATA实战
  15. vue 数组中嵌套数组_vue数组嵌套数组的问题
  16. 基于 Oauth 2.0 的第三方账号登录实现
  17. QT5.9.4 + cmake + VC2017 运行”run cmake“出现错误:xxx is not able to compile a simple test
  18. 2023湖北土建施工员证报考条件考试时间及报考流程 启程别
  19. 【蓝桥杯嵌入式】第十三届蓝桥杯嵌入式省赛客观题以及详细题解
  20. 保安也有梦之Java学习

热门文章

  1. 【解决方案】快递代收点部署视频监控,EasyCVR视频融合平台来助力
  2. android view.isshown,源码解析view的显示判断用isShown()还是View.VISIBLE
  3. javacv opencv 多张图加入mp3的音频合成视频
  4. ffmpeg命令行,单张图片,音频合成视频
  5. RDF(Resource Description Framework)
  6. C语言中函数参数传递的方式:值传递,地址传递
  7. LeetCode记录总结
  8. 科目二 车速忽快忽慢
  9. tp5设置参数全局过滤
  10. PS|001制作1寸照片