By changing the cadence of OpenJDK releases two years ago, Oracle accelerated the evolution of Java, which was categorically a positive move for the platform and the ecosystem. Before the change, developers were waiting for the new version with stable features for at least three years. Today, we can admit that the Java run-time development process is iterative. Initially, new capabilities are injected into OpenJDK as preview features; the developer community is testing and giving its feedback to JEP leaders, and after a number of releases, the feature becomes standard. JDK 14 has sixteen new features in six areas: API, Runtime & Performance, Serviceability, Tools, Improved platforms support, and Deprecation.
API enhancements
- JEP-361: Switch Expressions (Standard)
- JEP-305: Pattern Matching for instanceof (Preview)
- JEP-359: Records (Preview)
- JEP-368: Text Blocks (Second Preview)
- JEP-370: Foreign-Memory Access API (Incubator)
Run-time and Performance
- JEP-358: Helpful NullPointerExceptions
- JEP-352: Non-Volatile Mapped Byte Buffers
- JEP-345: NUMA-Aware Memory Allocation for G1
Serviceability
- JEP-349: JFR Event Streaming
Tools
- JEP-343: Packaging Tool (Incubator)
Improved platforms support
Deprecation
- JEP-362: Deprecate the Solaris and SPARC Ports
- JEP-366: Deprecate the ParallelScavenge + SerialOld GC Combination
- JEP-363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector
- JEP-367: Remove the Pack200 Tools and API
Let’s look at some new features in details.
API enhancements
Switch Expressions (Standard) JEP-361
This feature extended switch statement, which can be used as an expression with the help of arrow (->), and now can yield/return the value.
Before JDK 14
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
System.out.println(6);
break;
case TUESDAY:
System.out.println(7);
break;
case THURSDAY:
case SATURDAY:
System.out.println(8);
break;
case WEDNESDAY:
System.out.println(9);
break;
}
JDK 14
JDK 14 makes the syntax more precise and removes the boilerplate.
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
Pattern Matching for instanceof (Preview) JEP-305
Before JDK 14
if (o instanceof Foo) {
Foo f = () o;
System.out.println(f.getName());
}
JDK 14
if (o instanceof Foo f) {
System.out.println(f.getName());
}
This is the first step to other changes. But it’s already possible to combine Switch expressions with instanceof pattern matching and create much cleaner code.
Before JDK 14
@Override
public void onReceive(Object msg) {
if (msg instanceof ClusterMessage) {
onMsg((ClusterMessage) msg);
} else if (msg instanceof RpcBroadcastMsg) {
onMsg((RpcBroadcastMsg) msg);
} .......
}
JDK 14
@Override
public void onReceive(Object msg) {
switch (msg) {
case ClusterMessage cm -> onMsg(cm);
case RpcBroadcastMsg rbm -> onMsg(rbm);
...
}
}
Records (Preview) JEP-359
Before JDK 14, a data class would look like below with getters, setters, equals, hashcode, toString, and so on. To somehow get rid of all that mess, a widely adopted Lombok library was created. Also, you could rely on your IDE.
public class Station {
private String name;
private Coordinates coordinates;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Coordinates getCoordinates() {
return coordinates;
}
public void setCoordinates(Coordinates coordinates) {
this.coordinates = coordinates;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PlainStation that = (PlainStation) o;
return Objects.equals(name, that.name) &&
Objects.equals(coordinates, that.coordinates);
}
@Override
public int hashCode() {
return Objects.hash(name, coordinates);
}
@Override
public String toString() {
return "PlainStation{" +
"name='" + name + '\'' +
", coordinates=" + coordinates +s
'}';
}
}
With JDK 14, the same data-class can be declared as Record with only one line of code. The class will already have all getters, setters etc.
public record RecordStation(String name, List<Coordinates> coordinates) {}
Text Blocks (Second Preview) JEP-368
In JDK 13, Text Blocks was introduced with JEP-355. JDK 14 evolves (or, better say, reconsiders) this feature, which is useful for some DSLs. For example, we used it for JOCL (Java binding for OpenCL)
private static String vertexShaderSource = """
#version 150 core
in vec4 inVertex;
in vec3 inColor;
uniform mat4 modelviewMatrix;
uniform mat4 projectionMatrix;
void main(void)
{
gl_Position =
projectionMatrix * modelviewMatrix * inVertex;
}
""";
The new Java language features have well-known analogs in Kotlin.
- Switch Expressions –> When Expression
- Records –> Data Classes
- Text Blocks –> Multiline String Literals
These features are already supported since IntelliJ IDEA 2020.1, while JetBrains engineers, together with Oracle and other OpenJDK contributors, worked on feature design and implementation.
Foreign-Memory Access API (Incubator) JEP-370
There are some third-party tools like Ignite, mapDB, and memcached to work with off-heap memory. Now Java will have its native API to do the same with new abstractions MemorySegment, MemoryAddress, and MemoryLayout.
Deprecation
Evolution is not just about adding new capabilities. Evolution is also a removal of rudiments. A new cadence allows quick disposal of outdated features. In JDK 14, the Solaris port will be decommissioned. Solaris 11 will be the end of support in 2035. Users who need to have Java for Solaris should stay on LTS versions: JDK 8 or JDK 11.
To download Java SE verified binaries of Liberica JDK 14, go here