Cannot make filter->forEach->collect in one stream?

Replace forEach with map.

 items.stream()
      .filter(s-> s.contains("B"))
      .map(s-> {s.setState("ok");return s;})
      .collect(Collectors.toList());

forEach and collect are both terminal operations - Streams must have just one. Anything that returns a Stream<T> is a intermediate operation, anything other is a terminal operation.


The forEach is designed to be a terminal operation and yes - you can't do anything after you call it.

The idiomatic way would be to apply a transformation first and then collect() everything to the desired data structure.

The transformation can be performed using map which is designed for non-mutating operations.

If you are performing a non-mutating operation:

 items.stream()
   .filter(s -> s.contains("B"))
   .map(s -> s.withState("ok"))
   .collect(Collectors.toList());

where withState is a method that returns a copy of the original object including the provided change.


If you are performing a side effect:

items.stream()
  .filter(s -> s.contains("B"))
  .collect(Collectors.toList());

items.forEach(s -> s.setState("ok"))