Allow new language features on older version targets?
zjx001202 at gmail.com
Tue Oct 12 08:14:45 UTC 2021
Starting from Java 9, Java began to iterate rapidly and introduced
many new features, which made Java more expressive and modern.
However, upgrading Java is always difficult and painful. It needs to
go through a series of cumbersome upgrade and migration processes.
In these steps, the transplantation at the syntax level is often easy,
because Java maintains good compatibility. However, due to subtle
changes in the behavior of the JVM and the standard library, it is
relatively difficult to upgrade the version of the java runtime.
At the same time, for client applications, upgrading the development
environment is much easier than upgrading the Java version of the
deployment environment (e.g., only Java 8 is currently available on
MIPS64el). For various reasons, a large number of users stay on the
old java version. According to the statistical report of JetBrains,
71% of users still regularly use Java 8.0 in 2021.
The most affected people are the developers of libraries. In order to
make the library more widely used, most library authors always need to
make their libraries use the lowest java version possible. This makes
it difficult for them to enjoy the expression upgrade brought by Java
This pain is not necessary. Although some language features of Java
require the cooperation of JVM and standard library, e.g. Record, but
this is not necessary for more features. At present, we can specify
the source version and target version respectively, but we can't make
the source version higher than the target version. I think this
artificial additional restriction can be removed after careful
consideration, so that more developers can enjoy the improvement of
expression ability brought by Java's new language features.
These features are pure language features that can be easily compiled
into older versions of Java bytecode:
* Milling Project Coin (JEP 213): Allow @SafeVargs on private instance
methods; Allow effectively-final variables to be used as resources
in the try-with-resources statement;Allow diamond with anonymous
classes if the argument type of the inferred type is denotable.
* Local-Variable Type Inference (JEP 286)
* Local-Variable Syntax for Lambda Parameters (JEP 323)
* Switch Expressions (JEP 361)
* Text Blocks (JEP 378)
* Pattern Matching for instanceof (JEP 394)
* Pattern Matching for switch (JEP 406)
* Record Patterns & Array Patterns (JEP 405)
These characteristics cannot be directly desugared, but can be accepted
by the old runtime:
* module-info.java (JEP 261): At present, it is a popular practice to
use Java 8 compilation library and add module info to it. However,
this practice has not been well supported by the official. Even
with a build tool like gradle, it needs to be implemented by
special means. If javac can accept module info when the target
version is less than 9 and compile it to Java 9, it is very helpful
to simplify modular existing code.
* Allow interface methods to be private (JDK-8071453): This seems to
be allowed in jvmls 8, but it was not until Java 9 that it was
introduced into the Java language.
* Sealed Classes (JEP 409): Javac generates PermittedSubclasses_attribute
for sealed classes. This attribute will be ignored on the old
runtime and will not destroy the program. Even if it cannot be
guaranteed by the runtime before JDK 15, it can enhance the
expressiveness of the language and make the code more compatible
with the higher version runtime.
* Universal Generics (JDK-8261529): Universal generics seem to
compile well into bytecode compatible with older Java version.
I think it is particularly important to allow use of universal
generic in older bytecodes. This allows the library to adapt it
without compromising compatibility with older Java versions. This
can erase many obstacles to Valhalla's promotion.
Now we can use some hacks to do similar things, like
But this is just hack. It is unofficial and non-standard. At the same
time, it also lacks tool support.
We can also choose to switch to kotlin or Scala, both of them can emit
Java 8 bytecode. In fact, because of the need for compatibility, the
new language features of Java can't bring us more attraction because
we can't use it most of the time. Over time, kotlin and Scala, which
can have more language features on Java 8, have attracted us more and
more. These problems are not just in the Java 8 era. The need to be
compatible with old Java versions always exists, which makes it difficult
for many people to put new features of the Java language into production
for a long time. This will make Java less competitive with other JVM
More information about the jdk-dev