Java 8 流 - 收集与减少
你什么时候会使用 vs ?有没有人有很好的,具体的例子来说明什么时候走一条路或另一条路肯定更好?collect()
reduce()
Javadoc 提到 collect() 是一种可变的缩减。
鉴于这是一种可变的减少,我认为它需要同步(内部),这反过来又会对性能造成不利影响。据推测,它更容易并行化,但代价是必须在减少的每一步后创建一个新的数据结构来返回。reduce()
然而,上述陈述是猜测,我希望专家在这里插话。
你什么时候会使用 vs ?有没有人有很好的,具体的例子来说明什么时候走一条路或另一条路肯定更好?collect()
reduce()
Javadoc 提到 collect() 是一种可变的缩减。
鉴于这是一种可变的减少,我认为它需要同步(内部),这反过来又会对性能造成不利影响。据推测,它更容易并行化,但代价是必须在减少的每一步后创建一个新的数据结构来返回。reduce()
然而,上述陈述是猜测,我希望专家在这里插话。
reduce
是一个“fold”操作,它对流中的每个元素应用二元运算符,其中运算符的第一个参数是前一个应用程序的返回值,第二个参数是当前流元素。
collect
是一个聚合操作,其中创建一个“集合”,并将每个元素“添加”到该集合中。然后将流不同部分中的集合相加。
您链接的文档给出了采用两种不同方法的原因:
如果我们想获取一个字符串流并将它们连接成一个长字符串,我们可以通过普通的归约来实现这一点:
String concatenated = strings.reduce("", String::concat)
我们将得到预期的结果,它甚至可以并行工作。但是,我们可能不满意性能!这样的实现将执行大量的字符串复制,并且运行时的字符数将为 O(n^2)。一种更高性能的方法是将结果累积到StringBuilder中,StringBuilder是用于累积字符串的可变容器。我们可以使用与普通约简相同的技术来并行化可变约简。
所以关键是两种情况下的并行化是相同的,但是在这种情况下,我们将函数应用于流元素本身。在这种情况下,我们将函数应用于可变容器。reduce
collect
原因很简单:
collect()
只能使用可变结果对象。reduce()
旨在处理不可变的结果对象。reduce()
与不可变“示例public class Employee {
private Integer salary;
public Employee(String aSalary){
this.salary = new Integer(aSalary);
}
public Integer getSalary(){
return this.salary;
}
}
@Test
public void testReduceWithImmutable(){
List<Employee> list = new LinkedList<>();
list.add(new Employee("1"));
list.add(new Employee("2"));
list.add(new Employee("3"));
Integer sum = list
.stream()
.map(Employee::getSalary)
.reduce(0, (Integer a, Integer b) -> Integer.sum(a, b));
assertEquals(Integer.valueOf(6), sum);
}
collect()
与可变“示例例如,如果您想手动计算总和,则无法使用,而只能使用来自。看:collect()
BigDecimal
MutableInt
org.apache.commons.lang.mutable
public class Employee {
private MutableInt salary;
public Employee(String aSalary){
this.salary = new MutableInt(aSalary);
}
public MutableInt getSalary(){
return this.salary;
}
}
@Test
public void testCollectWithMutable(){
List<Employee> list = new LinkedList<>();
list.add(new Employee("1"));
list.add(new Employee("2"));
MutableInt sum = list.stream().collect(
MutableInt::new,
(MutableInt container, Employee employee) ->
container.add(employee.getSalary().intValue())
,
MutableInt::add);
assertEquals(new MutableInt(3), sum);
}
这是有效的,因为累加器不应该返回带有结果的新对象,而是要更改类型可变对象的状态。container.add(employee.getSalary().intValue());
container
MutableInt
如果你想改用,你不能使用这个方法,因为它是不可变的。(除此之外,这不会工作,因为没有空的构造函数)BigDecimal
container
collect()
container.add(employee.getSalary());
container
BigDecimal
BigDecimal::new
BigDecimal