Java 8 применить функцию ко всем элементам потока без разрыва цепочки потоков

есть ли способ в Java, чтобы применить функцию ко всем элементам Stream без нарушения ? Я знаю, что могу позвонить forEach, но этот метод возвращает void, а не Stream.

5 ответов


есть (по крайней мере) 3 способами. Для примера кода я предположил, что вы хотите вызвать 2 потребительских метода methodA и methodB:

Используйте peek():

list.stream().peek(x -> methodA(x)).forEach(x -> methodB(x));

хотя в документах говорится, что он используется только для "отладки", он работает (и сейчас он находится в производстве)

B. Использование map() чтобы вызвать methodA, затем верните элемент обратно в поток:

list.stream().map(x -> {method1(x); return x;}).forEach(x -> methodB(x));

это, вероятно, самый "приемлемый" подход.

C. сделайте две вещи в forEach():

list.stream().forEach(x -> {method1(x); methodB(x);});

это наименее гибкий и не может удовлетворить ваши потребности.


вы ищете Stream ' s


не совсем уверен, что вы имеете в виду breaking the stream chain, но любая операция на Stream что возвращает Stream не будет перерыв или потреблять ваш поток. Потоки, потребляемые terminal operations и, как вы отметили forEach не возвращает a Stream<T> и как таковой заканчивается поток, выполнив все intermediate операции перед forEach и самой forEach.

в Примере, который вы указали в комментарии:

 myStream.map(obj -> {obj.foo(); return obj;}

вы не можете сделать это с одним лайнером. Конечно, вы можете использовать ссылку на метод, но тогда ваш returned Stream будет другого типа (при условии foo возвращает тип):

  myStream.map(Obj::foo) // this will turn into Stream<T>, where T is 
           // the return type of foo, instead of Stream<Obj>

кроме того, что ваш map операция stateful, что сильно обескураживает. Ваш код будет компилироваться и может даже работать так, как вы хотите, но позже он может потерпеть неудачу. map операции должны быть stateless.


Я думаю, что вы ищете Stream.peek. Но внимательно прочитайте документы, поскольку он был разработан в основном как метод отладки. Из документов:

этот метод существует в основном для поддержки отладки, где вы хотите видеть элементы, когда они проходят мимо определенной точки в конвейере

акция прошла в peek должно быть не вмешиваясь.


лучший вариант, который у вас есть, - применить карту к вашему потоку. который возвращает поток, состоящий из результатов применения данной функции к элементам этого потока, например:

IntStream.rangeClosed(40, 70).limit(20).mapToObj(i -> (Integer) i).map(item->item+3).map(item->item*2)... 

(поток элементов типа StreamItemABC)

мы применяем несколько модификаций к потоку, но таким образом мы не можем передать какие-либо аргументы методу map, чтобы исправить его:

private void applyMethod(ParameterX parX) {
 someStreamX().map(n -> methodX(n, parX))...
}

private StreamItemABC methodX (StreamItemABC item, ParameterX parX) {
  return notification;
}