2016-05-12 2 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 с ценами и рассчитать сумму цен, используя один поток времени? Thanks

UPD: В результате мне нужен myList, заполненный ценой и суммой переменной с суммой. Но не с помощью usding stream() дважды для этого.

+4

Сбор элементов потока в списке, а также суммирование их в переменную требует побочных эффектов, которые не рекомендуется для потоков (как описано в документах Oracle для потоков) –

+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 ответ, если вы заинтересованы в использовании parallelStream с несовпадающей коллекцией, которая имеет смысл, поскольку сумма является неловко параллельной задачей.

+0

Имеет ли newList тот же самый порядок цен, что и исходный список? – Jack

2

Вы могли бы сделать идентичность отображение а добавить транзитное значение в список

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

Но я бы для решения Сулеймана Jneidi, используя быстрый взгляд(), его более изящным

+0

Мне также нужен myList, который также содержит цены. Ваш пример просто получает сумму. – Jack

+0

забыл «сквозное» сопоставление, помогает ли это сейчас? –

+0

Да, спасибо! похоже, что карты могут быть изменены друг с другом в этом примере. – Jack

7

Что вы хотите здесь, чтобы собрать свои элементы внутри 2 коллекционеров: первый из них будет собираться в список, а второй - суммой цены.

Поскольку в самом API-интерфейсе Stream нет таких коллекционеров, мы можем легко построить наш собственный. Давайте создадим класс 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

Это единственное чистое решение для API 'Stream'. – 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

Список, возвращенный 'Collectors.toList() 'может быть эффективно пройден (в настоящее время это просто' ArrayList'), а потоки, созданные из него, - это просто обертки вокруг этой возможности, т. е. поток выполняет итерацию по внутреннему массиву этого списка. В Java нет структуры данных, которая может быть пройдена быстрее ... – Holger