0

I wonder if there is any performance differences in two below scenarios - peek() vs map() with return:

Set<Item> convertedItems = items
                .stream()
                .filter(item -> ItemType.POSTER.equals(item.getType()))
                .peek(item -> item.setType(ItemType.LOGO))
                .collect(toSet());

or

Set<Item> convertedItems = items
                .stream()
                .filter(item -> ItemType.POSTER.equals(item.getType()))
                .map(item -> {
                    iitem.setType(ItemType.LOGO);
                    return item;
                })
                .collect(toSet());

I read several post on stackoverflow about setters in map() vs peek() and I found only one information about performance. It said that map() with return would be worse but without explaining why: How to call setter in chain of Stream

Jake
  • 19
  • 4
  • 1
    what do you care about? correctness or performance? because in your first example, `peek` could be entirely skipped by the implementation. – Eugene Aug 29 '19 at 14:59
  • 2
    Well, `peek()` doesn't have to create a new stream as it will just call the function on the current item and be done. However, I'd not bother with those differences but rather ask why use a stream to set the title on "converted" items? Do you realize that calling `setTitle()` will cause the elements in `items` to be changed as well because they _are_ the same elements? – Thomas Aug 29 '19 at 15:01
  • 1
    Since you are interested in performance: Have you already benchmarked either implementation? What kind of real-world values do you expect for set size? Are there other portions of your system that could yield much larger performance improvements than this microoptimization? – nanofarad Aug 29 '19 at 15:17
  • I'm really sorry. I edited my question. I made a mistake and while trying to give the simplest example I unnecessary removed filter() method. – Jake Aug 29 '19 at 15:29
  • @AndreyAkhmetov I didn't tested it yet. This method is used while fetching dependent entities. I don't have access to production environment and I'm not sure if I will able to make proper test on my local machine. Whole ideas happen in code review, probably it would not have a big impact on performance. – Jake Aug 29 '19 at 15:31
  • 1
    @Thomas what do you mean with “create a new stream”? There is no relationship between the operation type and the number of stream instances. Each chained operation may return a new stream or modify the existing stream. In the reference implementation, there is no difference between these two operations. – Holger Aug 29 '19 at 16:18
  • @Holger you're right, my bad. I didn't look at the reference implementations and they are in fact the same. – Thomas Aug 30 '19 at 07:37
  • @Thomas thank You. Could you please give me some link or instruction how to get to reference implementation about peek() and map()? – Jake Aug 30 '19 at 09:25
  • Well, just look up the JDK sources online or import them into your favorite IDE. The IDE makes it easier because you'd then be able to directly list implementations of the `Stream` interface. – Thomas Aug 30 '19 at 10:05

1 Answers1

2

It does not entirely answer your question but would forEach maybe be more sensible. Because both peek and map are not what you need I think.

Please note that peek is intended for debugging, source: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-

I think the following code might be more optimal:

items.forEach(s -> s.setTitle("second"));
nanofarad
  • 40,330
  • 4
  • 86
  • 117
  • I edited my question. I made a mistake and while trying to give the simplest example I unnecessary removed filter() method. Because of filter() I could not use forEach. Thank you for answering. – Jake Aug 29 '19 at 15:28
  • 2
    Please note that a stream also has forEach. Depending on what content you need in your result you could still use that. Otherwise map would be better because of the api note I doubt the performance difference between the two of them is relevant in 99,9% of the cases – Martin van Wingerden Aug 29 '19 at 16:19
  • forEach would not work i my real scenario. I want to extract two sets of items collection. I have three conversions like in above example. One gets POSTERs, makes them LOGO. Another stream should find e.g. ARTWORK and convert them to AVATAR etc. Those converted sets of item are used later, I need to have them i different variables – Jake Aug 30 '19 at 09:24
  • Maybe it would then make sense to iterate once to split the sets and then once over each subset to set the title. I am thinking about converting it to a map with eg Collectors.partitioningBy() – Martin van Wingerden Aug 30 '19 at 09:29