Java 8 - 收集器Collectors

简介: Java 8 - 收集器Collectors

20200510181139786.png


Pre

我们前面学到了,流可以用类似于数据库的操作帮助你处理集合。

它们支持两种类型的操作:

  • 中间操作(如 filter 或 map )
  • 终端操作(如 count 、 findFirst 、 forEach 和 reduce )


中间操作可以链接起来,将一个流转换为另一个流。这些操作不会消耗流,其目的是建立一个流水线。


与此相反,终端操作会消耗流,以产生一个最终结果,例如返回流中的最大元素。它们通常可以通过优化流水线来缩短计算时间。


前面使用过了collect 终端操作了,当时主要是用来把 Stream 中所有的元素结合成一个 List 。


我们学习完收集器以后,会知道collect 是一个归约操作,就像 reduce 一样可以接受各种做法作为参数,将流中的元素累积成一个汇总结果。具体的做法是通过定义新的Collector 接口来定义的,因此区分 Collection 、 Collector 和 collect 是很重要的。


举几个例子,先感受下


对一个交易列表按货币分组,获得该货币的所有交易额总和(返回一个 Map<Currency,Integer> )

将交易列表分成两组:贵的和不贵的(返回一个 Map<Boolean, List<Transaction>> )

创建多级分组,比如按城市对交易分组,然后进一步按照贵的和不贵的分组(返回一个Map<Boolean, List<Transaction>> )。


我们来看下不是用流,是如何处理的

20210311224501861.png


如果用流呢?


20210311224531216.png

简介


Map<Currency, List<Transaction>> transactionsByCurrencies =
    transactions.stream().collect(groupingBy(Transaction::getCurrency));


这个例子清晰的展示了函数式编程相对于指令式编程的一个主要优势:只需指出希望的结果—“做什么”,而不用操心执行的步骤——“如何做” 。


这个例子中传递给 collect方法的参数是 Collector 接口的一个实现,也就是给 Stream 中元素做汇总的方法。 我们之前接触的toList 只是说“按顺序给每个元素生成一个列表”; groupingBy 说的是“生成一个Map ,它的键是(货币)桶,值则是桶中那些元素的列表”。


要是做多级分组,指令式和函数式之间的区别就会更加明显:由于需要好多层嵌套循环和条件,指令式代码很快就变得更难阅读、更难维护、更难修改。相比之下,函数式版本只要再加上一个收集器就可以轻松地增强功能了。


收集器用作高级归约


对流调用collect 方法将对流中的元素触发一个归约操作(由 Collector 来参数化)。

看个归约操作的示例: 遍历流中的每个元素,并让 Collector 进行处理


20210311225410806.png


一般来说, Collector 会对元素应用一个转换函数(很多时候是不体现任何效果的恒等转换例如 toList ),并将结果累积在一个数据结构中,从而产生这一过程的最终输出。

例如,

Map<Currency, List<Transaction>> transactionsByCurrencies =
    transactions.stream().collect(groupingBy(Transaction::getCurrency));


这个交易分组的例子中,转换函数提取了每笔交易的货币,随后使用货币作为键,将交易本身累积在生成的 Map 中。


Collector 接口中方法的实现决定了如何对流执行归约操作。但 Collectors 实用类提供了很多静态工厂方法,可以方便地创建常见收集器的实例,只要拿来用就可以了。最直接和最常用的收集器是 toList静态方法,它会把流中所有的元素收集到一个 List 中:

List<Transaction> transactions = transactionStream.collect(Collectors.toList());


预定义收集器


预定义收集器的功能,也就是那些可以从 Collectors类提供的工厂方法(例如 groupingBy )创建的收集器。

它们主要提供了三大功能:

  • 将流元素归约和汇总为一个值
  • 元素分组
  • 元素分区

后续的博文我们继续对这几类展开学习~

相关文章
|
6月前
|
Java
Java 8 Collectors 深入解析与示例
Java 8 Collectors 深入解析与示例
|
7月前
|
Java
Java8 Stream Collectors groupingBy使用
Java8 Stream Collectors groupingBy使用
Java流式操作——Collectors工具类
maxBy:获取流中最大元素;minBy:获取流中最小元素
|
Java
Java 8 - 收集器Collectors_实战
Java 8 - 收集器Collectors_实战
99 0
|
Java
Java 8 - 收集器Collectors_分区partitioningBy
Java 8 - 收集器Collectors_分区partitioningBy
125 0
|
安全 Java
Java 8 - 收集器Collectors_分组groupingBy
Java 8 - 收集器Collectors_分组groupingBy
312 0
|
Java 容器
Java 8 - 收集器Collectors_归约和汇总
Java 8 - 收集器Collectors_归约和汇总
98 0
|
1天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
1天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。
|
2天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
12 3