Are you sure about that? I've looked at the way invokedynamic generates lambdas, and it's just generating anonymous classes at runtime using ASM. Inlining is from the JIT and applies to anonymous classes as well. I'm pretty sure you can get the exact same results without invokedynamic, you just have a lot more .class files to distribute.
I think you got it right. According to Grzegorz Kossakowski's comment (which is more accurate than the misleading article) :
http://www.takipiblog.com/2014/01/16/compiling-lambda-expres... , Java 8's lambda's aren't particularly efficient. They do create an anonymous class instance at runtime, as you say. Scala closures are implemented in a similar way, without invokedynamic, and as he says, and currently there is no performance win from invokedynamic's use in Java 8 vs the Scala impl. But it does hold promise of future optimizations, as he says:
"However, the key thing about invokedynamic is that it's essentially a JVM-level macro that defers lambda translation strategy to LambdaMetaFactory which is a library class. If Java 9 or 10 gets more direct (and performant) support for lambdas that won't require classes and object allocations then it can swap implementation of LambdaMetaFactory and all _existing_ code written for Java 8 will get performance boost. That is the brilliance of using invokedynamic in context of translating lambdas. We'll have to wait for future versions of Java to experience those benefits, though."
Well, for one, Lambdas are desugared into methods, not anonymous classes. Early on they used anonymous classes because it was convenient but that wasn't the final translation strategy.
My impression from the openjdk code is that each lambda generates:
1. A method in its parent class.
2. An invokedynamic instruction at the call site.
The invokedynamic instruction calls LambdaMetafactory, which compiles an anonymous class at runtime that calls method #1. So the only benefit of using invokedynamic is fewer class files, by deferring generating them until runtime.
It was a misunderstanding on my part about where they were claiming the anonymous class was generated. Early versions of Lambda were nothing more than sugar on top of anonymous inner classes and the claim above sounded very similar to that. However, I see that inside the LambdaMetaFactory anonymous classes are generated based on the call site. Probably the biggest difference is that Java 8 can avoid an object allocation when the lambda doesn't capture. Not sure if Scala supports this but I'm sure that it could do it.