Breaking Java8 Lambdas

Java8 lambdas are a very useful construct. But it has its limitations and costs.

To a developer everything looks simple - you place a line of code and it gets executed. It is much more complex under the hood. Lambdas implementation is filled with gotchas.

In most cases Lambda becomes a private method on your class. The host method acquires its method handle via an invokedynamic call. The invocation is completed with an appropriate invokeinterface, invokestatic, etc. That is the first gotcha, if you are dealing with the bytecode - the private method does not appear to be used on the first sight. You static code analysis tool would need to parse out class constants and bootstrapped methods data for each lambda callsite to reliably discover unused private methods.

Another interesting technic is the way lambdas capture surrounding variables. Despite earlier intentions to be smart about it (using bridge methods or classes) everything is passed to the private method as its parameters. That leads to an interesting outcome. Java compiler will gladly build a method with 40 parameters, 100 parameters, 255 parameters... And if your static analysis tool would want to call out methods with too many parameters, it will need to handle compiler generated functions with a great care.

Did you notice the number 255? Of course it is not random. It is the maximum number of named method parameters Java bytecode allows. What if you try to capture more than 255 variables? Of course that will not work. Compiler would generate its interim code to implement the lambda, but its own bytecode translator will fail with a "too many parameters" error. And, since it does not have any line number information for a generated method, it will report the error against the very first line of you Java file. No matter if it is an import, package or even a comment.

Want to puzzle a CS professor with a cryptic error? Use that. Or a method with 7 levels of nested try-finally, but that is not unique to java8.

But there are benefits as well. Since code of the lambda is just a private method on a class, you can do everything you would normally do with it. You can mock it out in a unit test. You can call if via reflection. You can modify the code with a java agent.

I do not like the design of the bytecode side of Lambdas much. It makes reading bytecode so much harder... We do not have enough Java developers who can "speak" bytecode as it is already. This new inokedynamic - bootstrapped methods - method handles magic is going to scare away more youngsters.

But the design is brilliant. If it is a hack to JVM, it is an ingenious hack.

Posted On

Category:

Tags: / /