Java 21 represents a major milestone as the latest Long-Term Support release, bringing revolutionary changes to concurrent programming with Virtual Threads and significant language improvements. This LTS version standardizes pattern matching for switch statements, introduces record patterns, and provides safe string interpolation with templates. Java 21 focuses on performance, developer productivity, and modern programming paradigms.
September 2023
Java 21 represents a major milestone as the latest Long-Term Support release, bringing revolutionary changes to concurrent programming with Virtual Threads and significant language improvements. This LTS version standardizes pattern matching for switch statements, introduces record patterns, and provides safe string interpolation with templates. Java 21 focuses on performance, developer productivity, and modern programming paradigms.
Java 21 introduces Virtual Threads as a standard feature, revolutionizing concurrent programming by providing lightweight, high-throughput threads that can handle millions of concurrent operations efficiently. Virtual Threads eliminate the traditional thread-per-request model limitations, enabling scalable applications with minimal resource overhead and improved performance for I/O-bound workloads.
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.time.Duration;
// Create virtual threads easily
Thread.ofVirtual()
.name("worker-virtual-thread")
.start(() -> {
System.out.println("Running in: " + Thread.currentThread());
});
// Virtual thread executor for handling many concurrent tasks
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
// Submit 100,000 tasks efficiently
List<Future<String>> futures = new ArrayList<>();
for (int i = 0; i < 100_000; i++) {
final int taskId = i;
Future<String> future = executor.submit(() -> {
// Simulate I/O operation
Thread.sleep(Duration.ofMillis(100));
return "Task " + taskId + " completed";
});
futures.add(future);
}
// Collect results
for (Future<String> future : futures) {
System.out.println(future.get());
}
}
// HTTP server with virtual threads
import java.net.ServerSocket;
import java.net.Socket;
try (ServerSocket serverSocket = new ServerSocket(8080)) {
while (true) {
Socket clientSocket = serverSocket.accept();
// Handle each client in a virtual thread
Thread.ofVirtual().start(() -> {
try (clientSocket) {
// Handle client request
handleClient(clientSocket);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}Java 21 introduces String Templates as a preview feature, providing safe and efficient string interpolation that eliminates the need for string concatenation and format methods. This feature improves code readability, reduces the risk of injection attacks, and maintains type safety while making string manipulation more intuitive and performant.
// String templates for safe interpolation
public void demonstrateStringTemplates() {
String name = "Alice";
int age = 30;
// Basic string template
String greeting = STR."Hello, \{name}! You are \{age} years old.";
System.out.println(greeting); // Hello, Alice! You are 30 years old.
// Mathematical expressions
int x = 10, y = 20;
String calculation = STR."\{x} + \{y} = \{x + y}";
System.out.println(calculation); // 10 + 20 = 30
// Method calls in templates
String upperName = STR."Upper case: \{name.toUpperCase()}";
System.out.println(upperName); // Upper case: ALICE
// Multi-line templates
String report = STR."""
User Report:
Name: \{name}
Age: \{age}
Status: \{age >= 18 ? "Adult" : "Minor"}
""";
System.out.println(report);
// JSON template
String json = STR."""
{
"name": "\{name}",
"age": \{age},
"active": \{age >= 18}
}
""";
System.out.println(json);
}Java 21 standardizes pattern matching for switch statements, enabling more expressive and type-safe switch expressions. This feature allows developers to use patterns in switch cases, making code more readable and eliminating the need for multiple if-else statements. Pattern matching enhances type safety and provides a more functional programming approach to conditional logic.
// Pattern matching in switch expressions
public String formatValue(Object value) {
return switch (value) {
case String s -> "String: " + s;
case Integer i -> "Integer: " + i;
case Double d -> "Double: " + d;
case List<?> list -> "List with " + list.size() + " elements";
case Map<?, ?> map -> "Map with " + map.size() + " entries";
case null -> "null value";
default -> "Unknown type: " + value.getClass().getSimpleName();
};
}
// Pattern matching with guards
public String categorizeNumber(Object value) {
return switch (value) {
case Integer i when i > 0 -> "Positive integer: " + i;
case Integer i when i < 0 -> "Negative integer: " + i;
case Integer i -> "Zero";
case Double d when d > 0.0 -> "Positive double: " + d;
case Double d when d < 0.0 -> "Negative double: " + d;
case Double d -> "Zero double";
default -> "Not a number";
};
}
// Record patterns in switch
record Point(int x, int y) {}
record Circle(Point center, double radius) {}
record Rectangle(Point topLeft, Point bottomRight) {}
public String describeShape(Object shape) {
return switch (shape) {
case Circle(Point center, double radius) ->
"Circle at (" + center.x() + "," + center.y() + ") with radius " + radius;
case Rectangle(Point topLeft, Point bottomRight) ->
"Rectangle from (" + topLeft.x() + "," + topLeft.y() + ") to (" +
bottomRight.x() + "," + bottomRight.y() + ")";
default -> "Unknown shape";
};
}