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 )创建的收集器。

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

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

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

相关文章
|
1月前
|
Java
Java8 Stream Collectors groupingBy使用
Java8 Stream Collectors groupingBy使用
|
11月前
|
Java
Java流式操作——Collectors工具类
maxBy:获取流中最大元素;minBy:获取流中最小元素
|
Java
Java 8 - 收集器Collectors_实战
Java 8 - 收集器Collectors_实战
80 0
|
Java
Java 8 - 收集器Collectors_分区partitioningBy
Java 8 - 收集器Collectors_分区partitioningBy
85 0
|
安全 Java
Java 8 - 收集器Collectors_分组groupingBy
Java 8 - 收集器Collectors_分组groupingBy
160 0
|
Java 容器
Java 8 - 收集器Collectors_归约和汇总
Java 8 - 收集器Collectors_归约和汇总
68 0
|
Java
JAVA 使用 Stream 中 Collectors 工具类 基础操作
JAVA 使用 Stream 中 Collectors 工具类 基础操作
89 0
JAVA 使用 Stream 中 Collectors 工具类 基础操作
|
2天前
|
安全 Java
JAVA多线程通信新解:wait()、notify()、notifyAll()的实用技巧
【6月更文挑战第20天】Java多线程中,`wait()`, `notify()`和`notifyAll()`用于线程通信。在生产者-消费者模型示例中,它们确保线程同步。`synchronized`保证安全,`wait()`在循环内防止虚假唤醒,`notifyAll()`避免唤醒单一线程问题。关键技巧包括:循环内调用`wait()`,优先使用`notifyAll()`以保证可靠性,以及确保线程安全和正确处理`InterruptedException`。
|
2天前
|
安全 Java
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
【6月更文挑战第20天】JAVA多线程中,wait(), notify(), notifyAll()是Object类的关键同步机制。wait()让线程等待并释放锁,直到被notify()或notifyAll()唤醒或超时。它们必须在同步块中使用,持有锁的线程调用。notify()唤醒一个等待线程,notifyAll()唤醒所有。最佳实践包括:与synchronized结合,循环检查条件,避免循环内notify(),通常优先使用notifyAll()。
|
2天前
|
Java 程序员
从菜鸟到大神:JAVA多线程通信的wait()、notify()、notifyAll()之旅
【6月更文挑战第21天】Java多线程核心在于wait(), notify(), notifyAll(),它们用于线程间通信与同步,确保数据一致性。wait()让线程释放锁并等待,notify()唤醒一个等待线程,notifyAll()唤醒所有线程。这些方法在解决生产者-消费者问题等场景中扮演关键角色,是程序员从新手到专家进阶的必经之路。通过学习和实践,每个程序员都能在多线程编程的挑战中成长。