Java 21 APIs & Features

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.

Released: September 2023
Long-Term Support (LTS)
Long-Term Support

Java 21 Overview

Release Information

Release Date:

September 2023

Support Type:
Long-Term Support (LTS)

Quick Summary

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.

Top Features

  • Virtual Threads (Standard) - Revolutionary concurrent programming with Project Loom
  • Pattern Matching for switch (Standard) - Enhanced switch expressions with pattern matching
  • Record Patterns (Standard) - Deconstructing records in switch statements
  • String Templates (Preview) - Safe and efficient string interpolation
  • Sequenced Collections - Ordered collection interfaces and operations
  • Structured Concurrency (Preview) - Simplified concurrent programming patterns

API Examples

Virtual Threads (Standard)

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();
            }
        });
    }
}

String Templates (Preview)

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);
}

Pattern Matching for Switch (Standard)

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";
    };
}