2

My question is very similar to this one: Java 8 Streams: multiple filters vs. complex condition

Anyway this is not a duplicate, as internals of map and filter are very different. While filters reduce the number of elements over time, a different rationale is needed to decide which approach is best.

Still the question is identical: Which of the following two approaches is more efficient? Or is it actually the same, so I can decide by readability?

Approach 1:

Collection<Bar> in = ...;
Collection<Baz> out = in.stream().map(FooUtil::fromBar).map(BazUtil::fromFoo).collect(Collectors.toSet());

Approach 2:

Collection<Bar> in = ...;
Collection<Baz> out = in.stream().map(bar -> BazUtil.fromFoo(FooUtil.fromBar(bar))).collect(Collectors.toSet());

Edit: This is just an example with two steps. In my real use case I have a few more steps.

Edit 2: As discussed in the comments, there is basically no difference. Thus I go with the better readable option. If anybody stumbles upon this question, please read on in the linked question, as the same answer can be applied. Thus I'm now going to close my question as duplicate.

Community
  • 1
  • 1
Sebastian S
  • 4,420
  • 4
  • 34
  • 63
  • 2
    When in doubt, you should write a [JMH benchmark](http://openjdk.java.net/projects/code-tools/jmh/). – Tunaki Oct 15 '15 at 12:46
  • The first one seems to be more readable, maybe up to about 3 `map()` steps, after that you're probably better off creating a bespoke method for your map chain. I would avoid approach 2 in its pure form, I'd rather go with `private static Baz fromBar(Bar bar) { return BazUtil.fromFoo(FooUtil.fromBar(bar))); }` and then use that in my `map()` call. – biziclop Oct 15 '15 at 12:46
  • @biziclop Yes I have some more steps. My example is somehow simpliefied. – Sebastian S Oct 15 '15 at 12:50
  • I don’t think that there is a relevant difference. It’s also just a matter of readability. – Holger Oct 15 '15 at 12:51
  • @SebastianS I would definitely go for a separate method encapsulating the chain of transformations then. That's far easier to read and document. – biziclop Oct 15 '15 at 12:51
  • 1
    in addition to what @biziclop said you may want to check if there are any optimization opportunities that you can have by creating `Baz` directly from `Bar` without the intermediate `Foo`. – the8472 Oct 15 '15 at 12:52
  • 1
    With the help of lambda expressions and method references, streams are intended to introduce functional programming capabilities into Java. From this point of view, I think your first approach is definitely better. Anyway, the "transformations" will be the same in both approaches, so I don't see any performance issues here. – Jeff Morin Oct 15 '15 at 12:53
  • 1
    I will quote the accepted answer on the linked question `The bottom line is, don’t think about such performance differences below the odor detection threshold. Use what is more readable.`. I think this question is still a duplicate – Dici Oct 15 '15 at 12:57
  • @the8472 Ok, killing unnecessary object allocation is a valid point. But assuming this is not possible, will the optimizer collapse the two maps to one single function, so the result is essentially the same as when writing such a function by hand? – Sebastian S Oct 15 '15 at 12:57
  • @Dici I read that, but hoped for different reasoning from people, who know more about the compiler internals. – Sebastian S Oct 15 '15 at 12:59
  • @SebastianS It's not so much a question of knowing about compiler internals, but priorities. The difference is small enough that writing clean, readable code takes priority in all but the most extreme corner cases. And in those cases you will write a microbenchmark anyway. – biziclop Oct 15 '15 at 13:11
  • @biziclop I agree, this is basically, what Holger on the linked question says. If there is nothing more to say about chaining 20 steps, I will probably accept the linked answer, thus closing my question as duplicate. But currently I still hope, sombody might know something important, that I haven't thought about. – Sebastian S Oct 15 '15 at 13:21
  • @Sebastian S: the hotspot optimizer doesn’t care whether the code resides in a `Predicate` or `Function` implementation. It’s just a chain of invocations to it. – Holger Oct 15 '15 at 13:24
  • @Holger Ok thanks for pointing that out. In that case, I agree on closing this as a duplicate ;) – Sebastian S Oct 15 '15 at 13:36

0 Answers0