Java 20: what’s new ?

Java 20: what’s new ?

Now that Java 20 is features complete (Rampdown Phase One at the day of writing), it’s time to walk through all the functionalities that bring to us, developers, this new version.

This article is part of a series on what’s new on the last versions of Java, for those who wants to read the others, here are the links: Java 19, Java 18, Java 17, Java 16, Java 15, Java 14, Java 13, Java 12, Java 11Java 10, and Java 9.

We have to admit that there is not a lot of new things in this release. Of the 6 Java Enhancement Proposals (JEP) that have been released, only one is about a new language API: JEP 429 – Scoped Values, the others are iterations of existing features.

JEP 429 – Scoped Values

JEP 429 introduces Scoped Values which allow sharing of immutable data within and between threads.

Until now, to share data within a thread, Thread Locals were used. These are mutable and require a complex data structure whose cost is not in line with virtual threads which are light and cheap to build. Moreover, they were sometimes the cause of bugs, because their use was not necessarily well understood.

Since the support of thread locals with Loom was problematic, a new way to share data between threads has been proposed which is immutable and interfaces better with the Structured Concurrency API: Scoped Values.

Here is a very basic example:

private static final ScopedValue<String> USERNAME = ScopedValue.newInstance();

ScopedValue.where(USERNAME, "duke") // bind a value to the scope
    // start a thread that could access this value
    .run(() -> System.out.println("User: " + USERNAME.get())); 

It is also possible to call .call() with a Callable to return a value.

At the end of the run() method call, the scoped value will no longer have a value for the thread, which avoids any risk of memory leak.

More information in the JEP 429.

JEP-432 – Record Patterns (Second Preview)

The second preview of Record Patterns contains important changes, so it deserves a dedicated paragraph to present them.

If you don’t know Record Patterns yet, you can refer to my article Java 19: What’s new?

Three changes has been done:

  • Support for parameterized type inference for generic record patterns.
  • Support for record patterns in for loops (enhanced for statements).
  • Removed support for named record patterns.

The support of parameterized type inference for generic record patterns allows to omit the parameterized type in a record pattern if it can be inferred by the compiler. Surprisingly, the diamond (<>) operator has not been used, we can simply omit the parameterized type.

record Box<T>(T t) {}

static void test(Box<String> bo) {
    if (bo instanceof Box(var s)) { // Inferred to be Box<String>(var s)
        System.out.println("String " + s);
    }
}

The support of record patterns in for loops (enhanced for statements) allows direct access to the components of a record inside the body of a for loop.

record Point(int x, int y) {}

static void dump(Point[] pointArray) {
    for (Point(var x, var y) : pointArray) { // Record Pattern in header!
        System.out.println("(" + x + ", " + y + ")");
    }
}

Before JEP 432, it was possible to name a record pattern to, in a way, do pattern matching on the record and its components at the same time.

record Point(int x, int y) {}

static void noMorePossible(Point p) {
    if(p instanceof Point(int x, int y) p) {
        System.out.println("x=" + x + " y=" + y + "for the point " + p);
    }
}

This possibility has been removed, the above code will now generate an error at compile time. It is not yet known if this is permanent or if it could be supported later.

Features that remain in preview

The following features remain in preview (or in incubator module).

  • JEP-433 – Pattern Matching for switch (Fourth Preview): change in the exception thrown by a switch of an enum in the case where the switch is supposed to be exhaustive (one case for each value of the enum) but is not at runtime. The exception was of type IncompatibleClassChangeError and is now of type MatchException.
  • JEP-434 – Foreign Function & Memory API (Second Preview): minor evolution of the API to make it easier to use.
  • JEP-436 – Virtual Threads (Second Preview): no significant change, the feature remains in preview to have more feedback on its usage.
  • JEP-437 – Structured Concurrency (Second Incubator): added inheritance of scoped values (JEP 429)
  • JEP 438 – Vector API (Fifth Incubator) : small bugfixes and performance improvements.

For details on these, you can refer to my previous articles.

More information in the JEP 432.

Miscellaneous

Various additions to the JDK:

  • All constructors of the URL class have been deprecated, the URI class should be preferred over the URL class and, if necessary, usage of URI.toURL() to construct a URL object from a URI.
  • Matcher.hasMatch(), MatchResult.end(String), MatchResult.group(String), MatchResult.start(String)
  • Float.float16ToFloat(short): Returns the float value closest to the numeric value of the argument, which is a binary16 floating point value encoded in a short.
  • Float.floatToFloat16(float): Returns the binary16 floating point value, encoded in the nearest short of the argument.

All new JDK 20 APIs can be found in The Java Version Almanac – New APIs in Java 20.

Internal changes, performance, and security

Each new version of the JDK brings its performance optimizations (including GC and intrinsic methods), and security improvements.

On the performance side, we can note several improvements in the management of I/O via the BufferedInputStream, PushbackInputStream, SequenceInputStream and ZipInputStream classes.

Thomas Schatzl contributed an improvement to the G1 garbage collector which now uses only one bitmap to store the liveness information of the heap objects. This change reduces the native memory size used by G1 by exactly 1.5% of the heap size. More information in this article which also contains a complete reminder of the different phases of G1: Concurrent Marking in G1. Other changes have been made on the Garbage Collector side, you can find them in this article by Thomas Schatzl: JDK 20 G1/Parallel/Serial GC changes.

On the security side, the focus has been on strengthening JVM security, cryptographic algorithm performance, as well as adding JFR events for security monitoring. You can refer to Sean Mullan’s article for an exhaustive list of security changes included in this release: JDK 20 Security Enhancements.

Conclusion

This new version brings some minor changes to pattern matching, and some improvements in concurrent programming via the new Scoped Values API. So very little compared to the previous versions. The next release will also be the next LTS, I hope for this one, that some of the JEP that have been in preview for literally years, will be promoted to stable.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.