Java 8中的Spliterator、Collector和Stream的理解

151
我在理解Java 8中的Stream接口方面遇到了困难,特别是与SpliteratorCollector接口有关的部分。我的问题是,我根本无法理解SpliteratorCollector接口,因此Stream接口对我来说仍然有些模糊。

SpliteratorCollector究竟是什么,我该如何使用它们?如果我愿意编写自己的SpliteratorCollector(并可能在此过程中编写自己的Stream),我应该做什么,不应该做什么?

我阅读了网上散布的一些示例,但由于这里的所有内容仍然是新的且可能会更改,因此示例和教程仍然非常稀少。

4个回答

150

作为用户,您几乎肯定不需要处理Spliterator,只有在编写Collection类型并且还打算优化对它们的并行操作时才需要使用它。

值得一提的是,Spliterator是一种以易于拆分集合的方式操作集合元素的方法,例如因为您要并行化并希望一个线程处理集合的一部分,另一个线程处理另一部分等等。

实际上,您基本上永远不会把Stream类型的值保存到变量中。 Stream类似于Iterator,它是一次性使用的对象,您几乎总是在流畅的链中使用它,如Javadoc示例中所示:

int sum = widgets.stream()
                  .filter(w -> w.getColor() == RED)
                  .mapToInt(w -> w.getWeight())
                  .sum();

Collector 是类似于 map/reduce 的最通用、抽象的 "reduce" 操作版本;特别是,它需要支持并行化和终止步骤。一些Collector的示例包括:

  • 求和,例如 Collectors.reducing(0, (x, y) -> x + y)
  • StringBuilder 追加,例如 Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString)

32
Spliterator(s)还提供了一种流Iterable的方法,该Iterable不是Collection。 - Bohemian
2
我的意思是“reduce操作,就像在map/reduce中所指的那样”。 - Louis Wasserman
3
抱歉,正确的是Collector.of,而不是Collectors.of。 - Louis Wasserman
2
如果您能解释一下每个收集器的作用,那么您关于Collector的示例会更有用。 - MiguelMunoz
1
最初在Java8之前,遵循纯OOP范式,我不知道为什么Java8强制转向FP。使用Java8进行函数式编程范式不是看起来很奇怪吗?您使用OOP原则设计类层次结构,然后使用FP风格(使用Java8功能)填充方法。这就是使用Java8的想法吗? - overexchange
显示剩余2条评论

91

Spliterator的基本含义是“可分割迭代器”。

单个线程可以遍历/处理整个Spliterator,但Spliterator还有一个trySplit()方法,它将“拆分”一部分给其他人(通常是另一个线程)处理--留下当前spliterator更少的工作。

Collector结合了reduce函数的规范(来自于map-reduce),一个初始值和一个组合两个结果的函数(从而使来自Spliterated流的工作结果能够被组合)。

例如,最基本的收集器将具有0的初始值,将整数添加到现有结果中,并通过将它们相加来“组合”两个结果。从而对分裂的整数流进行求和。

请参见:


5

接口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:


如果操作成功执行...你可能需要重新措辞。tryAdvance javadoc 更清晰:如果仍有剩余元素,则对其执行给定的操作并返回true;否则返回false。 - Piro

4
以下是使用预定义集合器执行常见的可变规约任务的示例:
 // 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));

3
这并不回答提问者的问题,而且你的帖子中也没有任何解释或描述。 - Sid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接