我相信我可以在listOfPricedObjects上使用一个流操作来做下一步:
List<BigDecimal> myList = new ArrayList();
myList = listOfPricedObjects.stream().map(PricedObject::getPrice).collect(Collectors.toList());
BigDecimal sum = listOfPricedObjects.stream().map(PricedObject::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add)
我如何用价格填充myList并使用流一次计算价格总和? 感谢
UPD:结果我需要myList填充价格和sum变量和sum。但不是两次使用stream()两次。
答案 0 :(得分:7)
你想要的是在2个收藏家中收集你的元素:第一个收集到列表中,第二个收集价格。
由于Stream API本身没有这样的收集器,我们可以轻松构建自己的收集器。让我们创建一个类ResultHolder
,它将保存Stream管道的结果:这是小数点和总和的列表。
class ResultHolder {
List<BigDecimal> list = new ArrayList<>();
BigDecimal sum = BigDecimal.ZERO;
}
最后,我们可以将其用于:
ResultHolder resultHolder =
listOfPricedObjects.stream()
.map(PricedObject::getPrice)
.collect(
ResultHolder::new,
(r, p) -> { r.list.add(p); r.sum = r.sum.add(p); },
(r1, r2) -> { r1.list.addAll(r2.list); r1.sum = r1.sum.add(r2.sum); }
);
System.out.println(resultHolder.list);
System.out.println(resultHolder.sum);
这将在并行管道中工作,并将保持列表的初始顺序,与其他答案相反。
答案 1 :(得分:6)
您可以使用peek
并在应用缩减时添加到新的list
List<BigDecimal> newList = new ArrayList<>();
BigDecimal sum = list.stream()
.map(PricedObject::getPrice)
.peek(newList::add)
.reduce(BigDecimal.ZERO, BigDecimal::add);
如果你对使用非并发收集的parallelStream
感兴趣,请查看Tunaki答案,这是有道理的,因为sum是一个令人尴尬的并行任务。
答案 2 :(得分:4)
虽然假设无法从源重新创建像listOfPricedObjects
之类的任意流并且因此只遍历一次的用例可能是合理的,您可以安全地假设遍历通过{{1生成的列表可以有效地遍历:
Collectors.toList()
此处没有代码重复,任何尝试在一次流遍历中执行这两个不相关的操作都会使代码更复杂而没有任何好处。
答案 3 :(得分:2)
您可以执行标识映射,将直通值添加到列表
BigDecimal sum = listOfPricedObjects.stream()
.map(o -> {
myList.add(o);
return o;})
.map(PricedObject::getPrice)
.reduce(BigDecimal.ZERO, BigDecimal::add)
但是我会使用peek()来寻找Sleiman Jneidi的解决方案,它更优雅