Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Java 8 code be compiled to run on Java 7 JVM?

People also ask

Can program developed with Java 7 be run on Java 8?

In general, no. The backwards compatibility means that you can run Java 7 program on Java 8 runtime, not the other way around. There are several reasons for that: Bytecode is versioned and JVM checks if it supports the version it finds in .

Can Java 11 compiled code run on Java 8 JVM?

The class files created by Java 8 are still executable in Java 11; however, there have been other changes in the Java runtime (library changes, etc.) that might require modification of the code. These modifications may be made in Java 8 and compiled with Java 8 making it compatible with the Java 11 runtime.

Can older JRE versions run Java program compiled with newer JDK versions?

For standard code, yes, it still works, but there are a few enterprise libraries that you can no longer rely on having present.

Is Jdk 17 backwards compatible?

In general Java is extremely backward compatible. There have been a few minor breaking changes from JDK 8 to JDK 17, but the worst ones have had command-line options to disable them.


No, using 1.8 features in your source code requires you to target a 1.8 VM. I just tried the new Java 8 release and tried compiling with -target 1.7 -source 1.8, and the compiler refuses:

$ javac Test -source 1.8 -target 1.7
javac: source release 1.8 requires target release 1.8

Default methods require such changes to the bytecode and the JVM that they would have been impossible to do on Java 7. The bytecode verifier of Java 7 and below will reject interfaces with method bodies (except for the static initializer method). Trying to emulate default methods with static methods on the caller side would not produce the same results, because default methods can be overridden in subclasses. Retrolambda has limited support for backporting default methods, but it can never be fully backported because it truly requires new JVM features.

Lambdas could run on Java 7 as-is, if the necessary API classes just would exist there. The invokedynamic instruction exists on Java 7, but it would have been possible to implement lambdas so that it generates the lambda classes at compile time (early JDK 8 builds did it that way) in which case it would work on any Java version. (Oracle decided to use invokedynamic for lambdas for future proofing; maybe one day JVM will have first-class functions, so then invokedynamic can be changed to use them instead of generating a class for every lambda, thus improving performance.) What Retrolambda does is that it processes all those invokedynamic instructions and replaces them with anonymous classes; the same as what Java 8 does at runtime when a lamdba invokedynamic is called the first time.

Repeating Annotations is just syntactic sugar. They are bytecode compatible with previous versions. In Java 7 you would just need to implement yourself the helper methods (e.g. getAnnotationsByType) which hide the implementation detail of a container annotation which contains the repeated annotations.

AFAIK, Type Annotations only exist at compile time, so they should not require bytecode changes, so just changing the bytecode version number of the Java 8-compiled classes should be enough to make them work on Java 7.

Method parameter names exist in the bytecode with Java 7, so that's also compatible. You can get access to them by reading the bytecode of the method and looking at the local variable names in the method's debug information. For example the Spring Framework does exactly that to implement @PathVariable, so there is probably a library method which you could call. Because abstract interface methods don't have a method body, that debug information doesn't exist for interface methods in Java 7, and AFAIK neither on Java 8.

The other new features are mostly new APIs, improvements to HotSpot and tooling. Some of the new APIs are available as 3rd party libraries (e.g. ThreeTen-Backport and streamsupport).

Summa summarum, default methods require new JVM features but the other language features don't. If you want to use them, you'll need to compile the code in Java 8 and then transform the bytecode with Retrolambda to Java 5/6/7 format. At minimum the bytecode version needs to be changed, and javac disallows -source 1.8 -target 1.7 so a retrotranslator is required.


As far as I know none of these changes in JDK 8 required the addition of new bytecodes. Part of the lambda instrumentation is being done using invokeDynamic (which already exist in JDK 7). So, from the JVM instruction set standpoint, nothing should make the codebase incompatible. There are, though, a lot of API associated and compiler improvements that would could make the code from JDK 8 difficult to compile/run under previous JDKs (but I have not tried this).

Maybe the following reference material can help somehow to enrich the understanding of how the changes related to lambda are being instrumented.

  • From Lambdas to Bytecode
  • Translations of Lambda Expressions

These explain in detail how things are instrumented under hood. Perhaps you can find the answer to your questions there.


If you are willing to use a "retrotranslator" try Esko Luontola's excellent Retrolambda: https://github.com/orfjackal/retrolambda