"peek" is to be primarily used for debugging. What if I want to call a method on a stream in the middle of a stream, something that changes the state of the streamed object.
Stream.of("Karl", "Jill", "Jack").map(Test::new).peek(t->t.setLastName("Doe"));
I could do:
Stream.of("Karl", "Jill", "Jack").map(Test::new).map(t->{t.setLastName("Doe"); return t;});
But that seems ugly. Is this something that shouldn't be done or is there a better way to do this?
EDIT: forEach
works except that it's a terminal operation, and so you can't keep working on the stream afterwards. I would then expect to make a Collection, do forEach, then start streaming the Collection again.
EDIT: map(Class::processingMethod)
is what I'm doing now, but since processingMethod
simply returns this
, it seems to be a misuse of map. Plus, it doesn't really read like business logic.
FINAL EDIT: I accepted @Holger's answer. Stream.peek
cannot be expected to process all the elements on a Stream because it is not a terminal operation. The same goes for map
. Even though you might have terminated your stream with something that guarantees it will process all operations, you should not be writing code that expects every user to do so. So, to do processing you should use forEach
on a Collection
, then start streaming the Collection
again if you want to.
If you have a small list, loops perform better. If you have a huge list, a parallel stream will perform better. Purely thinking in terms of performance, you shouldn't use a for-each loop with an ArrayList, as it creates an extra Iterator instance that you don't need (for LinkedList it's a different matter).
Again, the for- loop is faster that the sequential stream operation, but the difference on an ArrayList is not nearly as significant as it was on an array.
In java-8 the list is populated, but in jdk-9 peek is not called at all. Since you are not using filter or flatmap you are not modifying the size of the Stream and count only needs it's size; thus peek is not called at all. Thus relying on peek is a very bad strategy.
peek can get the smallest item directly compared with stream. foreach().
You are overusing method references. The simplicity of Test::new
is not worth anything, if it complicates the rest of your stream usage.
A clear solution would be:
Stream.of("Karl", "Jill", "Jack")
.map(first -> { Test t = new Test(first); t.setLastName("Doe"); return t; })
…
or much better
Stream.of("Karl", "Jill", "Jack").map(first -> new Test(first, "Doe")) …
assuming that the class has the not-so-far-fetched constructor accepting both names.
The code above addresses the use case, where the action manipulates a locally constructed object, so the action is only relevant if the object will be consumed by the subsequent Stream operations. For other cases, where the action has a side effect on objects outside the Stream, abusing map
has almost all of the drawbacks of peek
explained in “In Java streams, is peek really only for debugging?”
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With