Will code containing lambda expressions run on an

2019-04-03 07:03发布

问题:

This question already has an answer here:

  • Are compiled Java 8 lambda expressions backwards compatible with earlier versions of the Java runtime? 4 answers

Lambdas were introduced in Java8. Will code containing lambda expressions run on an older JVM, say, for java 1.6? I am concerned about binary compatibility not source code compatibility. It is a simple Yes/No question.

Thanks.

回答1:

Oracle tries very hard to keep the Java language and the JVM bytecode language separate. The Java Language Specification only says what a program that contains a lambda expression means, it doesn't say anything about how this program is supposed to be compiled or interpreted.

This means specifically that there is nothing in the Java Language Specification that forbids that lambda expressions are compiled in such a way that the resulting code can be executed by a Java 6 JVM, but there is nothing in the Java Language Specification that guarantees it either. Every Java vendor is allowed to encode lambda expressions in whatever way they want. (Obviously, for pragmatic reasons, most try to match whatever Oracle does pretty closely. That way, for example, debuggers / de-compilers / tools which can understand and reverse-engineer lambdas encoded by Oracle's javac will automatically work with bytecode produced by IBM J9 JDK's Java compiler.)

The javac compiler which ships with the Oracle JDK encodes lambda expressions using a rather complicated machinery of LambdaMetafactory, MethodHandles, and invokedynamic. The latter was only introduced in the Java 7 JVM, so this means that the specific encoding that Oracles JDK's javac uses requires at least a Java 7 JVM. But other encodings are definitely possible, none of this complex machinery is truly necessary, it is just a performance optimization. You could e.g. encode Lambda Expressions as inner classes, which would work down to the Java 1.1 JVM – this is after all exactly how we have written "poor man's lambdas" up to Java 8; it's also how original proposals for lambdas and even early previews of Java 8 implemented it, after all, the development of lambdas in Java pre-dates even Java 7 and invokedynamic.

There is a compiler called RetroLambda, which compiles Java 8 JVM bytecode (not Java source code!) produced by Oracle JDK javac to Java 7 JVM bytecode, Java 6 JVM bytecode, or Java 5 JVM bytecode. Using this compiler, you can produce a class file containing bytecode that will run on any Java 5 or newer JVM from Java 8 source code that uses (almost) all features of Java 8.



回答2:

Short answer: it depends.

If you are completely restricted to Oracle javac and libraries, the answer is: no; for the following reasons.

Java bytecode contains a major version number. By default, a Java 8 compiler puts java8 into the data. Any older JVM simply refuses to run that code. It is possible though to tell a Java 8 compiler to create bytecode compatible to older JVMs. But: in order for the older JVM to execute such "special" class files, you need all its dependencies to be available!

And there it breaks: Lambdas make use of the invokedynamic bytecode instruction which doesn't exist in Java 6. And beyond that, the compiler makes use of a large number of Java library stuff when compiling lambdas - all of them added after java 6.

So even when you would manage to compile lambda using source code to Java 6 bytecode - that instruction isn't available,and you need to provide all those other classes, too.

But: as the other great answer explains, there are alternatives to javac which allow you to use lambdas on older JVMs.

But: be careful how to spend your energy. Java 6 is still dead for "server side java". So using these alternatives is OK for platforms like Android, but when you are still running an Oracle Java 6 JVM somewhere, you should rather spend your energy on upgrading that system to a current version of Java.



回答3:

As others said: no

The class files produced by the javac compiler are versioned. Everything that is produced by Java 8 is flagged to require a Java 8 JVM by default. Older versions of the JVM won't accept the binary.

If you want to compile for an older platform, you have to tell javac: javac -target 6. As soon as you add this option to the command line, your Java 8 compiler will require that you specify -source 6 (or lower) as well. Therefore it will not accept any code that contains lambda expressions.