21

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? ;-)

Kalamar Obliwy
  • 861
  • 2
  • 8
  • 13
  • Check this answer to the same question with java 7 and 6: http://stackoverflow.com/questions/17347589/verify-java-version-compatibility/17347680#17347680 [1]: http://stackoverflow.com/questions/17347589/verify-java-version-compatibility/17347680#17347680 – MoYapro Jan 09 '14 at 07:46
  • Yeah I was thinking about it, because AFAIK no new bytecode instructions are added, so maybe if you compile it it has a possiblity to run.. – Kalamar Obliwy Jan 09 '14 at 07:57

3 Answers3

33

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.

Community
  • 1
  • 1
eis
  • 51,991
  • 13
  • 150
  • 199
  • 1
    @KalamarObliwy do you think there's something missing or wrong here, as the answer was unaccepted? – eis Jan 16 '14 at 09:54
-4

It is not possible, if you compile things in newer Java version they'll be un executable.

  • 5
    not true, you can use `-target` when compiling with java 8 to make .classes that work on java 7. However, you won't get java 8 features such as lambdas then. – eis Jan 09 '14 at 07:50
-4

You ca easily achieve this in maven pom.xml with plugin:

<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
        <source>1.8</source>
        <target>1.7</target>
        <compilerArgument></compilerArgument>
    </configuration>
 </plugin>

just as indicated that you can compile under 1.8 and to 1.6 which might have best compatibility with JavaSE 6

Rugal
  • 2,612
  • 1
  • 15
  • 16
  • This will compile the 1.8 code if I use non-1.7 features - lambdas to be precise? – Kalamar Obliwy Jan 09 '14 at 08:12
  • @KalamarObliwy As 1.7 have no lambda expression, you could not use that! – Rugal Jan 09 '14 at 08:18
  • 2
    @Rugal but that was the thing OP was asking for. This is the same thing as `-source` and `-target` options of javac, compiler plugin doesn't add any functional benefit there. – eis Jan 09 '14 at 08:20
  • @KalamarObliwy agreed, I know `javac` has this option. what I provide is a convenient way to achieve that! – Rugal Jan 09 '14 at 08:24
  • @Rugal I tried your pom snippet in a simple project using Maven 3.1.1 but the compilation fails independently of Java file contents. Are you sure this is working for you? – mikewse May 09 '14 at 10:49
  • I came here precisely because this does not work! – El Marce Jan 21 '15 at 08:19
  • using the code verbatim as it is here will lead to build failure, and with `-X` you'll see the reason: "javacTask: source release 1.8 requires target release 1.8" – eis Sep 20 '15 at 06:57
  • Please check this out http://stackoverflow.com/a/22492421 – john Nov 13 '15 at 05:17
  • The conclusion is, you couldn't compile higher version code with lower version compiler especially it contains some new features that could not be recognized by the low compiler. Using the code block I provided Will only enable you to freely compile any lower versioned code when using a high version compiler. – Rugal Jan 28 '16 at 18:12