理解 Java 8 中的 Spliterator、Collector 和 Stream
Posted
技术标签:
【中文标题】理解 Java 8 中的 Spliterator、Collector 和 Stream【英文标题】:Understanding Spliterator, Collector and Stream in Java 8 【发布时间】:2013-10-14 15:53:18 【问题描述】:我无法理解 Java 8 中的 Stream
接口,尤其是与 Spliterator
和 Collector
接口有关的地方。我的问题是我根本无法理解Spliterator
和Collector
接口,因此Stream
接口对我来说仍然有些晦涩。
Spliterator
和 Collector
到底是什么,我该如何使用它们?如果我愿意写我自己的Spliterator
或Collector
(在这个过程中可能还有我自己的Stream
),我应该做什么和不做什么?
我阅读了一些分散在网络上的示例,但由于这里的所有内容都是新的并且可能会发生变化,因此示例和教程仍然非常稀少。
【问题讨论】:
【参考方案1】:您几乎可以肯定永远不必以用户身份与Spliterator
打交道;仅当您自己编写 Collection
类型并且还打算优化它们的并行化操作时,才需要这样做。
对于它的价值,Spliterator
是一种操作集合元素的方式,可以很容易地分离出集合的一部分,例如因为您正在并行化并希望一个线程处理集合的一部分,一个线程处理另一部分,等等。
您基本上也不应该将Stream
类型的值保存到变量中。 Stream
有点像Iterator
,因为它是一次性使用的对象,您几乎总是会在流畅的链中使用它,就像在 Javadoc 示例中一样:
int sum = widgets.stream()
.filter(w -> w.getColor() == RED)
.mapToInt(w -> w.getWeight())
.sum();
Collector
是“reduce”操作(如 map/reduce)的最通用、最抽象的版本;特别是,它需要支持并行化和最终化步骤。 Collector
s 的示例包括:
Collectors.reducing(0, (x, y) -> x + y)
StringBuilder 附加,例如Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString)
【讨论】:
Spliterator(s) 还提供了一种流式传输不是集合的 Iterable 的方法 我的意思是“reduce 操作,在 map/reduce 中这个词的意思”Collectors.of
是旧的测试版方法已被删除还是我遗漏了什么?为了完整起见,(x,y) -> x+y
可以写成Integer::sum
。
呃,不,抱歉,这是 Collector.of,而不是 Collectors.of。
如果你能解释你的每个收集器的作用,你的收集器示例会更有用。【参考方案2】:
Spliterator
基本意思是“可拆分的迭代器”。
单线程可以遍历/处理整个 Spliterator 本身,但 Spliterator 也有一个方法 trySplit()
它将“拆分”一个部分供其他人(通常是另一个线程)处理 - 留下当前的 spliterator减少工作量。
Collector
将reduce
函数(map-reduce 成名)的规范与一个初始值和一个组合两个结果的函数组合在一起(从而使来自分离的工作流的结果能够被组合。)
例如,最基本的 Collector 的初始值为 0,将一个整数添加到现有结果中,并通过添加两个结果来“组合”它们。从而对拆分的整数流求和。
见:
Spliterator.trySplit()
Collector<T,A,R>
【讨论】:
合并两个结果的值? @JasonLaw -- 澄清!感谢您的建议。【参考方案3】:以下是使用预定义收集器执行常见可变归约任务的示例:
// Accumulate names into a List
List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
// Accumulate names into a TreeSet
Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
// Convert elements to strings and concatenate them, separated by commas
String joined = things.stream()
.map(Object::toString)
.collect(Collectors.joining(", "));
// Compute sum of salaries of employee
int total = employees.stream()
.collect(Collectors.summingInt(Employee::getSalary)));
// Group employees by department
Map<Department, List<Employee>> byDept
= employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
// Compute sum of salaries by department
Map<Department, Integer> totalByDept
= employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.summingInt(Employee::getSalary)));
// Partition students into passing and failing
Map<Boolean, List<Student>> passingFailing =
students.stream()
.collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
【讨论】:
这并没有回答Op的问题,而且您的帖子也没有任何解释或描述。【参考方案4】:接口Spliterator
- 是Streams 的核心功能。
stream()
和 parallelStream()
默认方法在 Collection
接口中提供。这些方法通过调用spliterator()
来使用Spliterator:
...
default Stream<E> stream()
return StreamSupport.stream(spliterator(), false);
default Stream<E> parallelStream()
return StreamSupport.stream(spliterator(), true);
...
Spliterator 是一个内部迭代器,可将流分成更小的部分。这些较小的部分可以并行处理。
在其他方法中,理解Spliterator有两个最重要的:
boolean tryAdvance(Consumer<? super T> action)
与Iterator
不同,它尝试对下一个元素执行操作。
如果操作执行成功,该方法返回true
。否则,返回false
- 这意味着不存在元素或流的结尾。
Spliterator<T> trySplit()
此方法允许根据一个或另一个标准(文件大小、行数等)将一组数据拆分为许多较小的集合。
【讨论】:
´如果操作成功执行..´ 您可能应该改写它。 tryAdvance javadoc 更清楚:'如果存在剩余元素,则对其执行给定的操作,返回 true;否则返回 false。'以上是关于理解 Java 8 中的 Spliterator、Collector 和 Stream的主要内容,如果未能解决你的问题,请参考以下文章
java 数据结构之arraylist Spliterator 使用和源码解析
Duplicate methods named spliterator with the parameters () and () are inherited from the types Colle