Getting Started With Java 21
Introduction
JDK 21, the open-source reference implementation of Java SE Platform version 21, was released on 19 September 2023.
It will be considered a long-term support (LTS) release from most vendors, the previous version having this kind of support being JDK 17. You can overview the key features and changes from Java 11 to Java 17 in the following article.
Production-ready builds of JDK 21 can be downloaded from the following sources:
Eclipse Temurin (successor of AdoptOpenJDK): Provides prebuilt OpenJDK binaries using an open source build & test infrastructure, for more many platforms (such as Linux, Windows and macOS).
Azul Zulu: provides many certified builds of OpenJDK for a wide array of platforms.
Oracle JDK: Commercial Oracle branded builds of the JDK. Free to use in production and free to redistribute, at no cost, under the Oracle No-Fee Terms and Conditions (NFTC) License.
Key features since Java 17
Record Patterns
Record patterns provide a concise way to unpack nested values from record objects.
record Point(int x, int y) {}
static void printSum(Object obj) {
// the x and y properties are extracted/unpacked from obj, similar to Destructuring in JavaScript
if (obj instanceof Point(int x, int y)) {
System.out.println(x+y);
} else {
System.out.println("Not a Point");
}
}
public static void main(String[] args) {
printSum(new Point(1, 2));
printSum(null);
}
Output:
3
Not a Point
Pattern Matching for switch
In Java 21, switch became more expressive and safe by covering more cases and allowing pattern matching.
static String patternSwitchTest(Object obj) {
return switch (obj) {
// The null check can now be handled inside the switch statement
case null -> "null";
// `Integer i` is a pattern. This case label will be matched if obj is of type Integer (and thus not with an equality test)
case Integer i -> String.format("int: %d", i);
case Long l -> String.format("long: %d", l);
case Double d -> String.format("double: %f", d);
// An additional boolean expression (guard) can now be specified with when clauses. This is referred to as guarded case labels.
case String s when s.isBlank() -> "Blank String";
case String s -> String.format("String: %s", s);
default -> obj.toString();
};
}
public static void main(String[] args) {
System.out.println(patternSwitchTest(3.14d));
System.out.println(patternSwitchTest("text"));
System.out.println(patternSwitchTest(null));
System.out.println(patternSwitchTest(" "));
}
Output:
double: 3.140000
String: text
null
Blank String
With enums
sealed interface Day permits WorkingDay, WeekendDay {}
enum WorkingDay implements Day {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY}
enum WeekendDay implements Day {SATURDAY, SUNDAY}
static String patternSwitchWithEnumTest(Day day) {
return switch (day) {
case WeekendDay weekendDay -> "Not a working day";
// Case constants can use qualified names of enum constants even if the switch selector expression is not of the enum type
case WorkingDay.FRIDAY -> "Last working day";
// We will get an error if we don't cover all cases in the switch: exhaustiveness is checked
default -> "Working day";
};
}
public static void main(String[] args) {
System.out.println(patternSwitchWithEnumTest(WorkingDay.MONDAY));
System.out.println(patternSwitchWithEnumTest(WeekendDay.SATURDAY));
System.out.println(patternSwitchWithEnumTest(WorkingDay.FRIDAY));
}
Output:
Working day
Not a working day
Last working day
Sequenced Collections
New collection interfaces were introduced in Java 21 that allows accessing and processing their elements in a well defined encounter order: SequencedCollection, SequencedMap and SequencedSet.
public static void main(String[] args) {
// `SequencedCollection` is implemented by `List` and `Deque`, and it's extended by the `SequencedSet` interface
SequencedCollection<String> collection = Arrays.asList("first value", "second value", "last value");
// `SequencedCollection` has many methods: addFirst, addLast, getFirst, getLast, removeFirst, removeLast
System.out.print("collection.getLast(): ");
System.out.println(collection.getLast());
// `SequencedMap` is implemented by `LinkedHashMap` and extended by the `SortedMap` interface
SequencedMap<String, String> map = new LinkedHashMap<>();
map.putFirst("first key", "first value");
map.putLast("last key", "last value");
System.out.print("map: ");
System.out.println(map);
// `SequencedSet` is implemented by `LinkedHashSet` and extended by the `SortedSet` interface
SequencedSet<String> sequencedMap = new LinkedHashSet<>(map.sequencedValues());
sequencedMap.removeLast();
System.out.print("sequencedMap: ");
System.out.println(sequencedMap);
// `sequencedKeySet` and `sequencedValues` are methods defined in the new `SequencedMap` interface
// `reversed` is a method defined in the new `SequencedSet` and `SequencedMap` interfaces
SequencedSet<String> reversedSet = map.sequencedKeySet().reversed();
// `unmodifiableSequencedSet` is a new method defined in the `Collections` utility class
SequencedSet<String> unmodifiableSequencedSet = Collections.unmodifiableSequencedSet(reversedSet);
System.out.print("unmodifiableSequencedSet: ");
System.out.println(unmodifiableSequencedSet);
}
Output:
collection.getLast(): last value
map: {first key=first value, last key=last value}
sequencedMap: [first value]
unmodifiableSequencedSet: [last key, first key]
Virtual Threads
Java 21 introduced Virtual Threads as an alternative way to write concurrent programs. They are lightweight because they use less OS resources compared to traditional Platform Threads.
They can be started using java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor()
or with the java.lang.Thread
Builder API such as Thread.ofVirtual()
ans Thread.startVirtualThread(Runnable)
Other features
A more exhaustive list of features and changes in JDK 21 integrated since JDK 17 can be found here.
IntelliJ IDEA support for Java 21
IntelliJ IDEA added comprehensive support for Java 21 features starting from the 2023.3
release. The latest version can be downloaded from this link.
To create and run your Java 21 project using IntelliJ IDEA - 2023.3
or a more recent version:
- From the top bar, select File -> New -> Project...
- Choose or download a JDK 21 and create your project
- Create a
Main
class with the following content for testing:public class Main { record Point(int x, int y) {} static void printSum(Object obj) { // the x and y properties are extracted from obj in Java 21 if (obj instanceof Point(int x, int y)) { System.out.println(x+y); } else { System.out.println("Not a Point"); } } public static void main(String[] args) { printSum(new Point(1, 2)); } }
- Run the project (use the play icon next to the main method). You should have
3
printed on the console without any errors.
Eclipse support for Java 21
Full support to new Java 21 language features was added to Eclipse starting from the 2023-12
release. The latest version can be downloaded from this link.
To create and run your Java 21 project using Eclipse IDE for Java Developers - 2023-12
or a more recent version:
- From the top bar, select File -> New -> Java Project
- Select
Configure JREs...
- Select
Add...
and chooseStandard VM
. PressNext
- Select
Directory...
, browse and choose your JDK 21 installation directory you have downloaded. PressFinish
- Select the JRE you have just added. Press
Apply and Close
- Enter your project name and select
JavaSE-21
as the execution environment JRE. After customizing your project pressFinish
- Create a
Main
class with the following content for testing:public class Main { record Point(int x, int y) {} static void printSum(Object obj) { // the x and y properties are extracted from obj in Java 21 if (obj instanceof Point(int x, int y)) { System.out.println(x+y); } else { System.out.println("Not a Point"); } } public static void main(String[] args) { printSum(new Point(1, 2)); } }
- Run the project (right-click on the class name, then select Run As -> Java Application). You should have
3
printed on the console without any errors.
Tooling support for Java 21
Maven
The maven-compiler-plugin support Java 21 compilation using either of the following configuration in the pom.xml
:
<properties
<maven.compiler.release>21</maven.compiler.release>
<!-- ... -->
</properties>
or
<properties
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<!-- ... -->
</properties>
Gradle
Gradle supports Java 21 starting from the 8.4 release.
This version brings support for compiling, testing, and running JVM-based projects.
Support for running Gradle itself with Java 21 is expected in future versions.
Soufiane Sakhi is an AWS Certified Solutions Architect – Associate and a professional full stack developer.