Java8流将元素添加到列表并求和

Java8流将元素添加到列表并求和,java,collections,java-8,sum,java-stream,Java,Collections,Java 8,Sum,Java Stream,我相信我可以在listOfPricedObjects上使用一个流操作来完成下一步: List<BigDecimal> myList = new ArrayList(); myList = listOfPricedObjects.stream().map(PricedObject::getPrice).collect(Collectors.toList()); BigDecimal sum = listOfPricedObjects.stream().map(PricedObject:

我相信我可以在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)
List myList=new ArrayList();
myList=listOfPricedObjects.stream().map(PricedObject::getPrice).collect(Collectors.toList());
BigDecimal sum=listOfPricedObjects.stream().map(PricedObject::getPrice).reduce(BigDecimal.ZERO,BigDecimal::add)
如何用价格填写我的列表,并一次性使用stream计算价格之和? 谢谢


UPD:因此,我需要用价格填充myList,并用sum变量sum。但不能使用usding stream()两次进行此操作。

您可以进行标识映射,并将传递值添加到列表中

BigDecimal sum = listOfPricedObjects.stream()
                                    .map(o -> {
                                         myList.add(o); 
                                         return o;})
                                    .map(PricedObject::getPrice)
                                    .reduce(BigDecimal.ZERO, BigDecimal::add)

但是我会选择使用peek()的Sleiman Jneidi解决方案,它更优雅

您可以使用
peek
并在应用缩减时添加到一个新的
列表

List<BigDecimal> newList = new ArrayList<>();
BigDecimal sum = list.stream()
                     .map(PricedObject::getPrice)
                     .peek(newList::add)
                     .reduce(BigDecimal.ZERO, BigDecimal::add);
List newList=newarraylist();
BigDecimal sum=list.stream()
.map(PricedObject::getPrice)
.peek(新列表::添加)
.reduce(BigDecimal.ZERO,BigDecimal::add);

如果您有兴趣将
parallelStream
与非并发集合一起使用,请查看Tunaki答案,因为sum是一项令人尴尬的并行任务。这里您想要的是在两个收集器中收集您的元素:第一个将收集到一个列表中,第二个将汇总价格

由于流API本身中没有这样的收集器,因此我们可以轻松构建自己的收集器。让我们创建一个类
ResultHolder
,它将保存流管道的结果:这是小数和总和的列表

class ResultHolder {
    List<BigDecimal> list = new ArrayList<>();
    BigDecimal sum = BigDecimal.ZERO;
}

这将在并行管道中工作,并将保持列表的初始顺序,与其他答案相反。

虽然可以合理地假设在一些用例中,无法从源代码重新创建任意流,如
listOfPricedObjects
,因此只能遍历一次,您可以放心地假设,可以高效地遍历通过
收集器生成的列表。toList()

List<BigDecimal> myList = listOfPricedObjects.stream()
    .map(PricedObject::getPrice).collect(Collectors.toList());
BigDecimal sum = myList.stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
List myList=listOfPricedObjects.stream()
.map(PricedObject::getPrice).collect(Collectors.toList());
BigDecimal sum=myList.stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

这里没有代码重复,任何试图在一个流遍历中执行这两个不相关操作的尝试都会使代码更加复杂,而没有任何好处。

我还需要在myList中填写价格。您的示例只得到了总和。忘记了“传递”映射,现在这有帮助吗?是的,谢谢,它可以工作了!在本例中,映射似乎可以相互更改。在列表中收集流元素,同时将它们求和为变量需要副作用,这对于流是不鼓励的(如Oracle文档中针对流所述)。方法只做一件事的干净代码概念发生了什么变化?感谢您的回答。myList.stream()不应该创建一个效率低下的新流吗?
收集器返回的列表。toList()
可以有效地遍历列表(目前它只是一个
ArrayList
),从它创建的流只是围绕该功能的包装,即流正在该列表的内部数组上迭代。Java中没有可以更快地遍历的数据结构……newList的价格顺序是否始终与初始list相同?这是
API唯一干净的解决方案。
List<BigDecimal> myList = listOfPricedObjects.stream()
    .map(PricedObject::getPrice).collect(Collectors.toList());
BigDecimal sum = myList.stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO);