Cherry
Cherry

Reputation: 33544

Is there workaround to "return" stream from forEach method?

Say that there is a collection which is needed to be modified first and then filtered:

Collection<MyObject> collection = ...
Stream<MyObject> dummyVariable = collection.stream();
dummyVariable.forEach(i -> i.callModifyingFunc(args));
return dummyVariable.filter(i -> i.isNeeded);

Because forEach has void return type is it impossible to write code without dummyVariable. Is there any workaround to write all in one chain:

Collection<MyObject> collection = ...
return Stream<MyObject> dummyVariable = collection.stream().forEach(i -> i.callModifyingFunc(args)).filter(i -> i.isNeeded);

Upvotes: 0

Views: 141

Answers (2)

Holger
Holger

Reputation: 298153

If you return a Stream to a caller, you have no control over the terminal operation eventually chained by the caller. The terminal operation might process all elements, but it also might be short-circuiting and it might even be the case that the caller abandons the stream without ever applying a terminal operation at all.

If the modification is intended to just record whether an element has been processed, peek is the right choice.

But if you want to apply a modification to every element in either case, just do it straight-forward:

Collection<MyObject> collection = ...
collection.forEach(i -> i.callModifyingFunc(args));
return collection.stream().filter(i -> i.isNeeded);

If you want to ensure that the modification is only made when the caller commences a terminal operation, it’s a bit more complicated:

Collection<MyObject> collection = ...
Spliterator<MyObject> sp = collection.spliterator();
return StreamSupport.stream(() -> {
        collection.forEach(i -> i.callModifyingFunc(args));
        return sp;
    }, sp.characteristics(), false)
    .filter(i -> i.isNeeded);

This will perform the modification of all elements right before the Stream processing starts, i.e. before the execution of the terminal operation.

But you should rethink your requirement. Having to modify all elements before a stream processing sounds questionable. What will happen if two clients acquire a stream?

Upvotes: 2

Nick Vanderhoven
Nick Vanderhoven

Reputation: 3093

Just use map instead of forEach to chain the pipeline operations:

collection.stream()
          .map(i -> i.callModifyingFunc(args))
          .filter(i -> i.isNeeded);

Upvotes: 2

Related Questions