2016-05-12 46 views
4

我相信我能做到未来使用上listOfPricedObjects一个流操作:Java的8个流元素添加到列表中,总结

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充满价格和总和变量与总和。但是不能用stream()两次。

+4

收集列表中的流元素,同时将它们合并到一个变量中需要副作用,这对流是不鼓励的(如Oracle Streams中的文档所述) –

+0

只有一件事情的方法的干净代码概念发生了什么变化? –

回答

6

您可以使用peek并加入到一个新的list,同时将减少

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

,如果你有兴趣使用请看看Tunaki答案与非并发集合,这是有道理的,因为总和是一个尴尬的并行任务。

+0

newList是否始终与初始列表的价格相同? – Jack

2

你可以做一个身份映射直通值添加到列表中

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

但是我用PEEK(去苏莱曼Jneidi的解决方案),其更优雅

+0

我需要myList充满价格也。你的例子只是得到了总和。 – Jack

+0

忘了“pass-through”映射,现在有帮助吗? –

+0

是的,谢谢它的作品!看起来像这个例子中的地图可以相互改变。 – Jack

7

你想要在这里收集你的元素在两个收藏家里面:第一个收集到一个列表中,第二个收集价格。

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

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); 

这将在并行流水线工作,并将保留列表,这违背了其他答案的初始订单:

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

最后,我们可以使用它。

+1

这是'Stream' API唯一的干净解决方案。 – Flown

4

虽然假设无法从源重新创建像listOfPricedObjects这样的任意流并因此只遍历一次的用例可能是合理的,但可以安全地假定遍历通过Collectors.toList()生成的列表可以有效地遍历:

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

这里没有重复代码,并在一个流遍历执行这两个不相干的操作将使代码没有任何好处更复杂的任何企图。

+0

感谢您的回答。 myList.stream()是否应该创建一个效率低下的新流?收藏家返回的列表。 – Jack

+1

收藏家返回的列表。toList()'可以被有效地遍历(目前它只是一个'ArrayList'),而从它创建的流只是包装器的能力,即流正在迭代该列表的内部数组。 Java中没有可以更快地遍历的数据结构... – Holger