Introduction
Java 21 is a Long-Term Support (LTS) release that brings significant improvements and new features to the Java platform. It includes several finalized features that were in preview in earlier versions.
In this comprehensive guide, we'll explore all the major new features in Java 21 with practical code examples you can try in our Java Compiler.
Virtual Threads (JEP 444)
Virtual threads are lightweight threads that dramatically reduce the effort of writing, maintaining, and observing high-throughput concurrent applications.
Creating Virtual Threads
public class VirtualThreadExample {
public static void main(String[] args) throws InterruptedException {
// Create a virtual thread
Thread vThread = Thread.ofVirtual().start(() -> {
System.out.println("Hello from virtual thread!");
System.out.println("Thread: " + Thread.currentThread());
});
vThread.join();
// Using Executors
try (var executor = java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " running on " + Thread.currentThread());
});
}
}
}
}
Benefits of Virtual Threads
Record Patterns (JEP 440)
Record patterns allow you to deconstruct record values in pattern matching.
record Point(int x, int y) {}
record Rectangle(Point topLeft, Point bottomRight) {}public class RecordPatternExample {
public static void main(String[] args) {
Rectangle rect = new Rectangle(new Point(0, 0), new Point(10, 20));
// Record pattern with nested deconstruction
if (rect instanceof Rectangle(Point(int x1, int y1), Point(int x2, int y2))) {
int width = x2 - x1;
int height = y2 - y1;
System.out.println("Width: " + width + ", Height: " + height);
}
}
}
Pattern Matching for Switch (JEP 441)
Pattern matching for switch is now finalized, allowing more expressive switch statements.
public class PatternSwitchExample {
static String describe(Object obj) {
return switch (obj) {
case Integer i when i > 0 -> "Positive integer: " + i;
case Integer i when i < 0 -> "Negative integer: " + i;
case Integer i -> "Zero";
case String s when s.isEmpty() -> "Empty string";
case String s -> "String of length " + s.length();
case null -> "null value";
default -> "Unknown type";
};
}
public static void main(String[] args) {
System.out.println(describe(42));
System.out.println(describe(-10));
System.out.println(describe("Hello"));
System.out.println(describe(""));
System.out.println(describe(null));
}
}
Sequenced Collections (JEP 431)
New interfaces that define a common way to access first and last elements of collections.
import java.util.*;public class SequencedCollectionExample {
public static void main(String[] args) {
// SequencedCollection methods
List<String> list = new ArrayList<>(List.of("A", "B", "C"));
System.out.println("First: " + list.getFirst()); // A
System.out.println("Last: " + list.getLast()); // C
list.addFirst("Start");
list.addLast("End");
System.out.println("List: " + list);
// Reversed view
List<String> reversed = list.reversed();
System.out.println("Reversed: " + reversed);
}
}
String Templates (Preview)
String templates provide a safe and efficient way to embed expressions in strings.
// Note: This is a preview feature
public class StringTemplateExample {
public static void main(String[] args) {
String name = "Java";
int version = 21;
// String template (preview)
// String message = STR."Hello, \{name}! Welcome to version \{version}.";
// Current alternative
String message = String.format("Hello, %s! Welcome to version %d.", name, version);
System.out.println(message);
}
}
Summary
Java 21 brings powerful new features that make Java programming more expressive and efficient:
| Feature | JEP | Status |
| Virtual Threads | 444 | Final |
| Record Patterns | 440 | Final |
| Pattern Matching for Switch | 441 | Final |
| Sequenced Collections | 431 | Final |
| String Templates | 430 | Preview |