理解 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 接口,尤其是与 SpliteratorCollector 接口有关的地方。我的问题是我根本无法理解SpliteratorCollector 接口,因此Stream 接口对我来说仍然有些晦涩。

SpliteratorCollector 到底是什么,我该如何使用它们?如果我愿意写我自己的SpliteratorCollector(在这个过程中可能还有我自己的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)的最通用、最抽象的版本;特别是,它需要支持并行化和最终化步骤。 Collectors 的示例包括:

求和,例如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减少工作量。

Collectorreduce 函数(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&lt;? super T&gt; action)Iterator 不同,它尝试对下一个元素执行操作。 如果操作执行成功,该方法返回true。否则,返回false - 这意味着不存在元素或流的结尾。

Spliterator&lt;T&gt; 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

关于集合List的源码分析

求助……关于iterator

关于JAVA中的HashMap 和iterator的问题

理解 java 8 中的 Stream.generate 静态方法签名的问题