47

When using the Java compiler (javac), we can specify two kinds of compatibility. One is using -source and the other is using -target. What is the difference between these two?

For example, -source 1.5 and -target 1.6?

Also, is there any case where we use a different source and target compatibility level?

Nayuki
  • 17,911
  • 6
  • 53
  • 80
Adam Lee
  • 24,710
  • 51
  • 156
  • 236

3 Answers3

42

From the javac docs:

-source Specifies the version of source code accepted.

-target Generate class files that target a specified version of the VM. Class files will run on the specified target and on later versions, but not on earlier versions of the VM.

In your example:

-source 1.5 and -target 1.6

This would be used to make sure that the source code is compatible with JDK 1.5, but should generate class files for use on JDK 1.6 and later.

Quite why you would do this is another matter.

Community
  • 1
  • 1
skaffman
  • 398,947
  • 96
  • 818
  • 769
  • 2
    Note that I've found that `javac` does not support all combinations. Also I actually have a use-case. In Java 6 JAX-WS is built in, so I wanted to have a solution working on plain Java 6 without extra libraries. That solution then needed for a few customers to be executable on a Java 5 JVM (and JAX-WS brought in on the side) and the `@Override` syntax changed so it was not immediately compilable by Java 5 javac. (This was pre-maven, it might be easier to do today) – Thorbjørn Ravn Andersen May 19 '12 at 08:16
  • 2
    See also `-bootclasspath` as described further in [this answer](http://stackoverflow.com/a/10663478/418556). – Andrew Thompson May 19 '12 at 08:19
  • 1
    @skaffman - *"Quite why you would do this is another matter..."* - Java tries to interpret comments. If languages are not set properly, then the compile could fail because of an illegal character in the comments!!! Its sometimes easier to tell the compiler to stop interpreting the comments then, say, fix the copyright notice in hundreds of files. – jww Oct 13 '15 at 21:08
  • @skaffman: +1 for the "Class files will run on the specified target and on later versions, but not on earlier versions of the VM." – Gaurav Jun 11 '18 at 13:27
  • 1
    I wish you'd explained the why briefly as well. – aderchox Oct 24 '21 at 09:15
13

The -source indicates what level of compliance your source code has: are you using Annotations? Then you would need at least 1.5; are you using @override on interface implementations, you would need 1.6 etc

The -target specifies what Java version you want to be able to run your classes on. You could use a Java SE 7 compiler and compile to run on Java SE 1.5.

raphaëλ
  • 6,393
  • 2
  • 29
  • 35
7

This is mostly useful to produce a jar file working with an older version of Java. I believe that so far all JDKs are able to execute older version too, so there is no real reason to have target larger than source.

It does however make sense to set target to e.g. 1.6 when using a 1.7 JDK.

I'm not sure, but I believe it could work in some situations to compile a 1.7 java code using a 1.7 compiler to a 1.6 jar, for example expressions such as

ArrayList<Integer> foo = new ArrayList<>();

that are only valid in 1.7+ source version should compile to 1.6 compatible byte code. But I have not verified whether the compiler will actually do this. Unfortunately, this doesn't seem to be implemented in practise.

Has QUIT--Anony-Mousse
  • 76,138
  • 12
  • 138
  • 194
  • 5
    While it is a nice theory it will not actually do this in practice. If you try source 1.7 and target 1.6 you will get this error: "source release 1.7 requires target release 1.7" – Tomas Jul 25 '14 at 23:02
  • 7
    I found what @Tomas says to be true. Which is irritating, since that seems the most useful combination? It prevents you from writing libraries in 1.7 source level that could be linked in 1.6 projects. Is there any solution to this at all? – mxk Aug 09 '14 at 15:41
  • 1
    @Matthias There is no problem in linking libraries from different classfile versions. The only reason to use `-target 1.6` is if the JVM running the code is 1.6. – Nayuki May 15 '16 at 03:14
  • A target version lower than the source version would mean that the compiler would have to be able to compile new language features for an old runtime. While there may be cases where this could be possible, there definitely are those where it's not. For example, there is nothing you could do to a jar-file to faithfully mimic the behaviour of Project Valhalla's value types on a 1.6 JVM. Hence target version >= source version. 99% of the time you know what your target version is, and then set the source version to the same to have as much Java available at your fingertips as you can get. – Zyl Nov 28 '19 at 08:47
  • Valhalla is highly experimental. You can't expect much compatibility guarantees with it anyway. You can, however, expect JDK10 to be able to generate JDK8 compatible bytecode. The bigger problem usually is that you may be using some functions inadvertently that do not exist in JDK 8 yet. Such as using Path.of() instead of Paths.get() to convert a String to a NIO Path. It will generate *bytecode* for the Java 8 VM, but still require the later JRE. So this is mostly **useful if you have a Java 8 *source* that you need to compile to run on a Java 8 VM**, but your compiler is newer than 8. – Has QUIT--Anony-Mousse Nov 28 '19 at 18:46
  • @Anony-Mousse-ReinstateMonica Correct me if I'm wrong, but I think `-target` affects only bytecode generation, not the use of JRE APIs. In order to be API-safe I think you have to use something like the Animal Sniffer plugin – Rag Jan 08 '20 at 23:59