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);});
это наименее гибкий и не может удовлетворить ваши потребности.
не совсем уверен, что вы имеете в виду 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;
}