2016-05-12 72 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