Now that Java 21 is features complete (Rampdown Phase Two 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 20, Java 19, Java 18, Java 17, Java 16, Java 15, Java 14, Java 13, Java 12, Java 11, Java 10, and Java 9.
Java 21 is the new Long Term Support (LTS) version , which means it will be supported for two years. Given the number of JEPs (Java Enhancement Proposals) it contains – no fewer than 15 – it’s clear that this is a version rich in new features. But perhaps the most important (not to say exciting) one is the finalization of virtual threads! Virtual threads are lightweight threads with low creation and scheduling costs, making it easier to write concurrent applications. We’ll have to wait for the ecosystem to support them, but virtual threads will make Java relevant for highly concurrent applications in memory-constrained environments.
JEP 430 – String Templates (Preview)
Many languages support string interpolation. String interpolation is a string literal containing expressions as well as text literals.
For example, in Kotlin, "$x plus $y equals ${x + y}"
is a string containing the expressions $x
, $y
, and ${x + y}
, which will be replaced by their textual values. These values are said to be interpolated within the character string. This interpolation is carried out from the variables and enables operations between variables (in this case, an addition).
The problem with interpolation is that it’s dangerous as a global feature, because it doesn’t allow for validation or sanitization when constructing the final string. This exposes it, for example, to SQL or JavaScript injections.
In Java, String Templates offer string interpolation with validation and sanitization via a template processor.
A template processor takes a template, then interpolates the template to an object of a specific type; so from a template, you can interpolate a String
, or a PreparedStatement
, or a JSONObject
, … As it is possible to have several processors, each can implement a validation step if required.
Here’s an example of how to use the String Template STR
, which has no specific validation and can be used to replace string concatenation:
String firstName = "Loïc"; String lastName = "Mathieu"; String helloWorld = STR."Hello {firstName} {lastName}";
In Java, expressions are defined by {expression}
, and calling a template processor is done via its name, in this case FMT, which is a constant of the StringTemplate
interface that will have been previously imported via a static import.
There has been a lot of discussion around the choice of the expression format. Due to the existence of many libraries using $, # or {} as expression delimiters, the choice was for a format that is not valid outside String Templates: String s = "Hello {firstName} {lastName}"
does not compile. This distinguishes String Templates from simple Strings.
The standard library includes three template processors:
RAW
: processor that does not interpolate character strings, enables low-level manipulations.STR
: processor that interpolates a character string to another character string via simple concatenation.FMT
: processor that interpolates a character string to another character string, allowing expressions to be formatted via a Formatter, for exampleFMT."%05d{x} + %05d{y} = %05d{x + y}";
You can create your own processors by implementing the StringTemplate.Processor
interface.
More information in the JEP 430.
JEP 431 – Sequenced Collections
Java’s Collection API has seen an addition in Java 21 of a magnitude not seen for many, many releases!
Java collections don’t have a type representing an ordered sequence of elements, Java 21 fills this gap by introducing the SequencedCollection
, SequencedSet
and SequencedMap
interfaces. These interfaces provide methods for adding, modifying or deleting elements at the beginning or end of the collection, as well as for iterating over a collection in reverse order.
Here’s the SequencedCollection
interface:
interface SequencedCollectionextends Collection { SequencedCollection reversed(); void addFirst(E); void addLast(E); E getFirst(); E getLast(); E removeFirst(); E removeLast(); }
The reversed()
method will return a view of the collection in reversed order; a modification to the original collection will impact the reversed view.
SequencedSet
is a set that is also a SequencedCollection
, here is its interface:
interface SequencedSetextends Set , SequencedCollection { SequencedSet reverse