Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you compile a class using Java 8 and then use it in Java 7? [duplicate]

Tags:

Can you compile a class using Java 8 and then use it in Java 7?

I'd like to write a utility JAR with a simple interface (Java 7 compatible) but using lambdas all over the place inside. Then I'd like to use the utility in some code that has to be compiled with JDK 7..

is it possible?


As you can see, there are some contradictory answers.. so, what's the truth? ;-)

like image 217
Kalamar Obliwy Avatar asked Jan 09 '14 07:01

Kalamar Obliwy


People also ask

Is Java 8 backwards compatible?

Backward CompatibilityJava versions are expected to be binary backwards-compatible. For example, JDK 8 can run code compiled by JDK 7 or JDK 6. It is common to see applications leverage this backwards compatibility by using components built by different Java version.

How do I compile a different version of Java?

Yes, you can set the version of compiler at compile time. And compile your java code into old versions of java. Here we use javac to compile code that will run on a 1.4 VM. You might also need following parameter to set denote the version of your code.

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

As answered already you are mostly safe and most products and 3rd party libraries will simply work. However there do exist very rare cases where binary incompatibilities (ones where the class file compiled using older JDK will fail to run in the newer JVM) were introduced between JDK versions.


1 Answers

You can use -source 1.7 -target 1.7 when compiling with java 8 javac to make .classes that work on java 7. However, you don't get java 8 features such as lambdas then, as you have to use 1.7 as source value as well.

That's not the end of story though. In this answer it was explained that there aren't actually new JVM instructions, so this should be possible. In this answer the tool retrolambda was introduced which can be used to run java 8 code on older JVMs. Author claims that compilation step is not required, just a java agent transforming the classes. His solution deals with lambdas only, not any other features. Of course, that won't bring you the new APIs coming with java 8, or other improvements, but at least it would make what you ask possible. Some of the new apis have also been unofficially backported, namely java.util.stream and java.time.


If we were in pre-java8 era, even though -source 1.8 -target 1.7 is not supported by javac you could still use Compiler API to do the same. Also Eclipse compiler has been able to do this, as well as ant and maven tasks that use either of the two mentioned options (compiler-plugin uses javac by default). This doesn't seem to no longer be so straight forward, as using other compilers you'd need the implementations of features like lambdas as well, and Compiler API will throw the same "javac: source release 1.8 requires target release 1.8" as others.

For the interested, here's what happens going that way using Eclipse compiler & Maven and Calculator example code:

pom.xml:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>fi.eis.applications.java8</groupId>
  <artifactId>calculator</artifactId>
  <version>1.0-SNAPSHOT</version>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.3</version>
        <configuration>
          <source>1.8</source>
          <target>1.7</target>
          <compilerId>eclipse</compilerId>
        </configuration>
        <dependencies>
          <dependency>
            <groupId>org.codehaus.plexus</groupId>
            <artifactId>plexus-compiler-eclipse</artifactId>
            <version>2.6</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>
</project>

Execution on Windows:

>mvn clean compile
[..snip..]
[INFO] BUILD SUCCESS
>cd target\classes

>"%JAVA_HOME%\bin\java.exe" Calculator
Exception in thread "main" java.lang.NoClassDefFoundError: java/lang/invoke/LambdaMetafactory
        at Calculator.main(Calculator.java:16)
Caused by: java.lang.ClassNotFoundException: java.lang.invoke.LambdaMetafactory
        at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 1 more

So one would need to implement those classes in pure java as a third party library to get that to work.

like image 82
eis Avatar answered Oct 13 '22 17:10

eis