8

I'm working on a high-performance project where Java 8's lambda functions are enormously useful. I've found, however, that they're memory inefficient when used en masse. For example, suppose I need to apply a lambda function 1,000,000 times:

for (int i = 0; i < 1_000_000; i += 1) {
  collection.forEach(thing -> thing.foo());
}

In this form, thing -> thing.foo() seems to instantiate 1,000,000 objects, which has nasty speed ramifications when done repeatedly. My standard optimization, where necessary, has been to do the following refactoring:

Consumer<Thing> DoFoo = thing -> thing.foo(); 
for (int i = 0; i < 1_000_000; i += 1) {
  collection.forEach(DoFoo);
}

This removes the memory overhead and is trivial to do. This brings me to my question: if something so simple results in such big performance gains, why doesn't the Java compiler perform this refactoring for me? Are there other optimizations that could be made such that lambda performance/overhead is more predictable and efficient? If so, are they planned for release in future versions? Lambdas have proven wonderfully effective, but when I need to worry about low-level stuff when using them, it degrades the usefulness of their abstraction.

closed as primarily opinion-based by Thomas Owens Oct 6 '16 at 16:54

Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 3
    I'm voting to close this question as off-topic because we aren't the Java developers and can't be an authoritative source on their future plan. – Ixrec Jun 9 '16 at 6:48
  • 1
    How did you determine that thing -> thing.foo() gets instantiated on each pass? I tried writing a loop where each iteration ran System.out.println((Supplier<Object>) (() -> new Object())); twice, and I found that each iteration printed the same two instances. (As in, it appeared that each lexical occurrence of () -> new Object() resulted in only one lambda object being instantiated.) See ideone.com/4O0qqE. [continued] – ruakh Jun 9 '16 at 8:20
  • 3
    @Ixrec Some members might be. Or there might have been a draft spec. Perhaps there's a technical reason why this can't be done. I think it should stay open. – ColBeseder Jun 9 '16 at 12:50
  • 1
    @Jules: That's a good point. To address it, I've now edited the program to keep all instances alive (by using them as keys in a IdentityHashMap), and still see how many distinct instances there are (by printing out the IdentityHashMap at the end). As expected, it still shows that there are only two instances: ideone.com/4O0qqE. – ruakh Jun 9 '16 at 16:54
  • 2
    "why doesn't the Java compiler perform this refactoring for me?" Many programmers don't know that the Java Language and VM specs promise "precise exceptions." This helps portability tremendously but it severely limits optimizations like loop unrolling since an exception raised in code moved by the optimizers wouldn't occur at the right time. In theory the compiler + VM could make the exception look like it occurred at the right time, but only if it could roll back all intervening side effects. – Jerry101 Jul 20 '16 at 5:31