Java Versions
The beginning of the 6-month release cycle with major modularization features.
1. Module System - Java 9 (Project Jigsaw)
Section titled “1. Module System - Java 9 (Project Jigsaw)”Introduces a new level of abstraction above packages called modules, allowing better encapsulation and dependency management.
// module-info.java - defines module name, dependencies, and exportsmodule com.example.myapp { requires java.base; // Implicit dependency requires java.sql; // Explicit dependency exports com.example.myapp.api; // What this module exposes}2. JShell (REPL Tool) - Java 9
Section titled “2. JShell (REPL Tool) - Java 9”A Read-Eval-Print Loop tool for interactive Java programming, making it easier to test snippets.
# Command line usagejshell> int x = 10x ==> 10
jshell> String greeting = "Hello"greeting ==> "Hello"
jshell> System.out.println(x * 2)20
jshell> /vars # List all variables3. Factory Methods for Collections - Java 9
Section titled “3. Factory Methods for Collections - Java 9”Immutable collections created with concise factory methods, making code more readable.
// Create immutable collections easilyList<String> list = List.of("A", "B", "C");Set<String> set = Set.of("A", "B", "C");Map<String, Integer> map = Map.of("A", 1, "B", 2);
// For more than 10 entriesMap<String, Integer> bigMap = Map.ofEntries( Map.entry("A", 1), Map.entry("B", 2), Map.entry("C", 3));4. Private Interface Methods - Java 9
Section titled “4. Private Interface Methods - Java 9”Allows private methods in interfaces to share common code between default methods.
interface Calculator { default void add(int a, int b) { log("Adding: " + a + " + " + b); System.out.println(a + b); }
default void multiply(int a, int b) { log("Multiplying: " + a + " * " + b); System.out.println(a * b); }
// Private helper method - reduces code duplication private void log(String message) { System.out.println("LOG: " + message); }}5. Process API Improvements - Java 9
Section titled “5. Process API Improvements - Java 9”Better control and monitoring of operating system processes.
ProcessHandle current = ProcessHandle.current();System.out.println("PID: " + current.pid());
ProcessHandle.Info info = current.info();info.command().ifPresent(cmd -> System.out.println("Command: " + cmd));info.arguments().ifPresent(args -> System.out.println("Args: " + Arrays.toString(args)));
// List all running processesProcessHandle.allProcesses() .filter(ph -> ph.info().command().isPresent()) .limit(5) .forEach(ph -> System.out.println(ph.pid() + " " + ph.info().command()));6. Stream API Enhancements - Java 9
Section titled “6. Stream API Enhancements - Java 9”New methods for better stream manipulation: takeWhile, dropWhile, and iterate.
// takeWhile - takes elements while predicate is trueList<Integer> numbers = List.of(1, 2, 3, 4, 5, 1);List<Integer> result1 = numbers.stream() .takeWhile(n -> n < 4) // Takes 1, 2, 3, stops at 4 .collect(Collectors.toList()); // [1, 2, 3]
// dropWhile - drops elements while predicate is trueList<Integer> result2 = numbers.stream() .dropWhile(n -> n < 3) // Drops 1, 2, takes rest .collect(Collectors.toList()); // [3, 4, 5, 1]
// New iterate method with predicateStream.iterate(0, n -> n < 10, n -> n + 2) // Like for-loop .forEach(System.out::print); // 0 2 4 6 8Java 10 (March 2018)
Section titled “Java 10 (March 2018)”A feature release focusing on local variable type inference.
1. Local Variable Type Inference (var) - Java 10
Section titled “1. Local Variable Type Inference (var) - Java 10”Allows declaring local variables with var instead of explicit types, improving readability.
// Old wayMap<String, List<Map<String, Object>>> complexMap = new HashMap<>();
// New way with varvar complexMap = new HashMap<String, List<Map<String, Object>>>();
// More examplesvar list = new ArrayList<String>(); // Inferred as ArrayList<String>var stream = list.stream(); // Inferred as Stream<String>var path = Path.of("file.txt"); // Inferred as Path
// CANNOT use var for:// - Method parameters// - Return types// - Fields// - Lambda parameters// - Without initializer2. Unmodifiable Collection Methods - Java 10
Section titled “2. Unmodifiable Collection Methods - Java 10”New copyOf methods to create unmodifiable copies of collections.
List<String> original = new ArrayList<>();original.add("A");original.add("B");
List<String> copy = List.copyOf(original); // Unmodifiable copySet<String> setCopy = Set.copyOf(original); // Unmodifiable set copy
// These throw UnsupportedOperationException if modified// copy.add("C"); // ERROR!3. Optional.orElseThrow() - Java 10
Section titled “3. Optional.orElseThrow() - Java 10”Convenient method to get value or throw exception if empty.
Optional<String> optional = Optional.of("Hello");
// Old wayString value1 = optional.orElseThrow(() -> new RuntimeException());
// New concise way (Java 10)String value2 = optional.orElseThrow(); // Uses NoSuchElementException
// Equivalent toString value3 = optional.get(); // But with better semanticsJava 11 (September 2018)
Section titled “Java 11 (September 2018)”A Long-Term Support (LTS) release with significant features and removal of deprecated APIs.
1. HTTP Client (Standard) - Java 11
Section titled “1. HTTP Client (Standard) - Java 11”New modern HTTP client API supporting HTTP/2 and WebSocket, replacing HttpURLConnection.
HttpClient client = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_2) .connectTimeout(Duration.ofSeconds(10)) .build();
HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.example.com/data")) .header("Content-Type", "application/json") .GET() .build();
// Synchronous requestHttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());System.out.println("Status: " + response.statusCode());System.out.println("Body: " + response.body());
// Asynchronous requestclient.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(HttpResponse::body) .thenAccept(System.out::println);2. String Methods - Java 11
Section titled “2. String Methods - Java 11”New helpful methods for String manipulation.
String str = " Hello World ";
// isBlank() - checks if string is empty or only whitespaceSystem.out.println("".isBlank()); // trueSystem.out.println(" ".isBlank()); // trueSystem.out.println("a".isBlank()); // false
// strip() - better than trim() (Unicode aware)System.out.println("\u2000Hello\u2000".strip()); // "Hello"System.out.println(str.strip()); // "Hello World"
// stripLeading() and stripTrailing()System.out.println(str.stripLeading()); // "Hello World "System.out.println(str.stripTrailing()); // " Hello World"
// repeat()System.out.println("Java ".repeat(3)); // "Java Java Java "
// lines() - returns stream of linesString multiline = "Line1\nLine2\r\nLine3";multiline.lines().forEach(System.out::println);3. Local-Variable Syntax for Lambda Parameters - Java 11
Section titled “3. Local-Variable Syntax for Lambda Parameters - Java 11”Allows using var in lambda parameters for consistency.
// Before Java 11Predicate<String> oldWay = (String s) -> s.length() > 5;
// Java 11 - using var in lambdaPredicate<String> newWay = (var s) -> s.length() > 5;
// Useful when annotations are neededBiFunction<String, String, String> function = (@NonNull var s1, @NonNull var s2) -> s1 + s2;4. Running Java Files Without Compilation - Java 11
Section titled “4. Running Java Files Without Compilation - Java 11”Single-file source-code programs can be executed directly.
// File: HelloWorld.javapublic class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); }}
// Run directly without javac:// java HelloWorld.java5. Collection.toArray() - Java 11
Section titled “5. Collection.toArray() - Java 11”New default method to convert collections to arrays more conveniently.
List<String> list = List.of("A", "B", "C");
// Old wayString[] array1 = list.toArray(new String[0]);
// Java 11 wayString[] array2 = list.toArray(String[]::new); // Method referenceJava 12 (March 2019)
Section titled “Java 12 (March 2019)”A feature release with switch expressions preview and new string methods.
1. Switch Expressions (Preview) - Java 12
Section titled “1. Switch Expressions (Preview) - Java 12”New form of switch that can return values and eliminates fall-through (preview feature).
// Traditional switch statementint day = 3;String dayType;switch (day) { case 1: case 2: case 3: case 4: case 5: dayType = "Weekday"; break; case 6: case 7: dayType = "Weekend"; break; default: dayType = "Invalid";}
// New switch expression (preview in Java 12)dayType = switch (day) { case 1, 2, 3, 4, 5 -> "Weekday"; case 6, 7 -> "Weekend"; default -> "Invalid";};
// Can return valuesint numLetters = switch (day) { case 1 -> 6; // "Monday" case 2 -> 7; // "Tuesday" default -> 0;};2. String Methods - Java 12
Section titled “2. String Methods - Java 12”New methods for string transformation and indentation.
String text = "Hello\nWorld";
// indent() - adds or removes leading whitespaceSystem.out.println(text.indent(2)); // Adds 2 spaces at beginning of each lineSystem.out.println(text.indent(-2)); // Removes 2 spaces if present
// transform() - applies function to stringString result = "hello".transform(s -> s.toUpperCase()) .transform(s -> s + " WORLD");System.out.println(result); // "HELLO WORLD"3. Teeing Collector - Java 12
Section titled “3. Teeing Collector - Java 12”Special collector that merges two collectors’ results.
import static java.util.stream.Collectors.*;
List<Integer> numbers = List.of(10, 20, 30, 40);
// Calculate average and sum simultaneouslyrecord Stats(double average, int sum) {}
Stats stats = numbers.stream() .collect(teeing( averagingInt(i -> i), // First collector summingInt(i -> i), // Second collector Stats::new // Merge function ));
System.out.println("Average: " + stats.average()); // 25.0System.out.println("Sum: " + stats.sum()); // 100Java 13 (September 2019)
Section titled “Java 13 (September 2019)”Adds text blocks and enhances switch expressions.
1. Text Blocks (Preview) - Java 13
Section titled “1. Text Blocks (Preview) - Java 13”Multi-line string literals that automatically format strings.
// Old way - messy with escape sequencesString json = "{\n" + " \"name\": \"John\",\n" + " \"age\": 30\n" + "}";
// New way with text blocksString jsonBlock = """ { "name": "John", "age": 30 } """;
// HTML exampleString html = """ <html> <body> <h1>Hello, World!</h1> </body> </html> """;
// SQL queryString query = """ SELECT id, name, email FROM users WHERE active = true ORDER BY name """;2. Switch Expressions Enhancements - Java 13
Section titled “2. Switch Expressions Enhancements - Java 13”Adds yield keyword for returning values from switch branches.
int day = 2;String dayName = switch (day) { case 1 -> "Monday"; case 2 -> { System.out.println("It's Tuesday!"); yield "Tuesday"; // yield returns value from block } case 3 -> "Wednesday"; default -> "Unknown";};
// Traditional style with yieldint length = switch (dayName) { case "Monday": case "Friday": yield 6; case "Tuesday": yield 7; default: yield 0;};Java 14 (March 2020)
Section titled “Java 14 (March 2020)”Records, pattern matching for instanceof, and helpful NullPointerExceptions.
1. Records (Preview) - Java 14
Section titled “1. Records (Preview) - Java 14”Concise syntax for declaring data carrier classes.
// Old way - verbosepublic final class Person { private final String name; private final int age;
public Person(String name, int age) { this.name = name; this.age = age; }
// Getters, equals(), hashCode(), toString() methods...}
// New way with recordpublic record Person(String name, int age) { // Automatically gets: // - Private final fields // - Constructor // - Getters (name(), age()) // - equals(), hashCode(), toString()}
// UsagePerson person = new Person("Alice", 30);System.out.println(person.name()); // AliceSystem.out.println(person); // Person[name=Alice, age=30]
// Can add custom methodsrecord Employee(String name, int id, double salary) { public String toJson() { return String.format("{\"name\":\"%s\",\"id\":%d}", name, id); }}2. Pattern Matching for instanceof (Preview) - Java 14
Section titled “2. Pattern Matching for instanceof (Preview) - Java 14”Simplifies common pattern of instanceof check and cast.
// Old wayObject obj = "Hello";if (obj instanceof String) { String s = (String) obj; System.out.println(s.length());}
// New way with pattern matchingif (obj instanceof String s) { // s is automatically cast System.out.println(s.length()); // Can use s here}
// Can combine with conditionsif (obj instanceof String s && s.length() > 5) { System.out.println("Long string: " + s);}3. Helpful NullPointerExceptions - Java 14
Section titled “3. Helpful NullPointerExceptions - Java 14”NullPointerExceptions now show which variable was null.
public class HelpfulNPE { public static void main(String[] args) { Person person = null; // Old: NullPointerException (no details) // New: Cannot invoke "Person.getName()" because "person" is null System.out.println(person.getName()); }}
class Person { String getName() { return "John"; }}Java 15 (September 2020)
Section titled “Java 15 (September 2020)”Text blocks and records become standard, sealed classes preview.
1. Sealed Classes (Preview) - Java 15
Section titled “1. Sealed Classes (Preview) - Java 15”Restricts which classes can extend or implement a class/interface.
// Base sealed classpublic sealed class Shape permits Circle, Rectangle, Triangle { // Explicit permitted subclasses // Class definition}
// Final subclasspublic final class Circle extends Shape { private final double radius; // Implementation}
// Sealed subclasspublic sealed class Rectangle extends Shape permits Square { // Can further restrict // Implementation}
// Non-sealed subclass (allows unknown subclasses)public non-sealed class Triangle extends Shape { // Implementation - can be extended by any class}
// Records can be sealed toopublic sealed interface Expr permits ConstantExpr, PlusExpr, TimesExpr {
record ConstantExpr(int i) implements Expr {} record PlusExpr(Expr a, Expr b) implements Expr {} record TimesExpr(Expr a, Expr b) implements Expr {}}2. Text Blocks Become Standard - Java 15
Section titled “2. Text Blocks Become Standard - Java 15”Text blocks are no longer preview and include new escape sequences.
// Now standard featureString json = """ { "name": "John", "age": 30, "city": "New York" } """;
// New escape sequencesString singleLine = """ This is a single line \ that continues here \ but appears as one line""";// Result: "This is a single line that continues here but appears as one line"
// Escape newlineString noNewline = """ Line 1\ Line 2""";// Result: "Line 1Line 2"Java 16 (March 2021)
Section titled “Java 16 (March 2021)”Records, pattern matching, and sealed classes become standard features.
1. Records (Standard) - Java 16
Section titled “1. Records (Standard) - Java 16”Records are now a standard language feature.
// Full featured recordspublic record Point(int x, int y) { // Compact constructor for validation public Point { if (x < 0 || y < 0) { throw new IllegalArgumentException("Coordinates must be non-negative"); } }
// Custom methods public double distanceFromOrigin() { return Math.sqrt(x * x + y * y); }}
// Local records (inside methods)public class Geometry { public double calculateArea() { record Dimensions(double width, double height) {}
Dimensions dim = new Dimensions(10.5, 20.3); return dim.width() * dim.height(); }}2. Pattern Matching for instanceof (Standard) - Java 16
Section titled “2. Pattern Matching for instanceof (Standard) - Java 16”Pattern matching for instanceof is now a standard feature.
// Widely usable nowpublic void process(Object obj) { if (obj instanceof String s) { System.out.println("String length: " + s.length()); } else if (obj instanceof Integer i && i > 0) { System.out.println("Positive integer: " + i); } else if (obj instanceof List<?> list && !list.isEmpty()) { System.out.println("Non-empty list: " + list.get(0)); }}3. Stream.toList() - Java 16
Section titled “3. Stream.toList() - Java 16”Convenient method to collect stream elements to an unmodifiable list.
List<String> names = List.of("Alice", "Bob", "Charlie");
// Old wayList<String> result1 = names.stream() .filter(n -> n.startsWith("A")) .collect(Collectors.toList());
// New concise wayList<String> result2 = names.stream() .filter(n -> n.startsWith("A")) .toList(); // Returns unmodifiable list
// result2.add("David"); // Throws UnsupportedOperationExceptionJava 17 (September 2021)
Section titled “Java 17 (September 2021)”Long-Term Support (LTS) release with sealed classes becoming standard.
1. Sealed Classes (Standard) - Java 17
Section titled “1. Sealed Classes (Standard) - Java 17”Sealed classes are now a standard language feature.
// Define a sealed hierarchypublic sealed interface Vehicle permits Car, Truck, Motorcycle { String getType();}
public final class Car implements Vehicle { public String getType() { return "Car"; }}
public final class Truck implements Vehicle { public String getType() { return "Truck"; }}
public non-sealed class Motorcycle implements Vehicle { public String getType() { return "Motorcycle"; }}
// Using with pattern matchingpublic void processVehicle(Vehicle v) { switch (v) { case Car c -> System.out.println("It's a car"); case Truck t -> System.out.println("It's a truck"); case Motorcycle m -> System.out.println("It's a motorcycle"); // No default needed - exhaustiveness guaranteed by compiler }}2. Pattern Matching for switch (Preview) - Java 17
Section titled “2. Pattern Matching for switch (Preview) - Java 17”Extends pattern matching to switch expressions and statements.
// Pattern matching in switch (preview)Object obj = "Hello";
String result = switch (obj) { case Integer i -> String.format("int %d", i); case Long l -> String.format("long %d", l); case Double d -> String.format("double %f", d); case String s -> String.format("String %s", s); case null -> "It was null!"; default -> obj.toString();};
// Guarded patternsstatic String formatterPatternSwitch(Object obj) { return switch (obj) { case Integer i when i > 0 -> "Positive integer: " + i; case Integer i -> "Integer: " + i; case String s when s.length() > 5 -> "Long string: " + s; case String s -> "String: " + s; default -> "Unknown"; };}3. Strongly Encapsulate JDK Internals - Java 17
Section titled “3. Strongly Encapsulate JDK Internals - Java 17”Restricts access to internal JDK APIs by default.
// Many internal APIs now require --add-opens to access// Old code that might break:// sun.misc.BASE64Encoder // Use java.util.Base64 instead// sun.misc.Unsafe // Limited access
// Solution: Use public APIsimport java.util.Base64;
Base64.Encoder encoder = Base64.getEncoder();String encoded = encoder.encodeToString("data".getBytes());Java 18 (March 2022)
Section titled “Java 18 (March 2022)”Adds UTF-8 by default and simple web server.
1. UTF-8 by Default - Java 18
Section titled “1. UTF-8 by Default - Java 18”Makes UTF-8 the default charset for all Java APIs.
// Before Java 18: charset depended on platform// After Java 18: UTF-8 always used by default
String text = "Hello 世界";byte[] bytes = text.getBytes(); // Uses UTF-8 by defaultString decoded = new String(bytes); // Also UTF-8
// Still can specify charset explicitlybyte[] latinBytes = text.getBytes(StandardCharsets.ISO_8859_1);2. Simple Web Server - Java 18
Section titled “2. Simple Web Server - Java 18”Command-line tool and API for simple HTTP server.
# Command line usagejwebserver -p 8000 -b localhost
# Or programmaticallyimport com.sun.net.httpserver.SimpleFileServer;import java.net.InetSocketAddress;import java.nio.file.Path;
// Create simple file servervar server = SimpleFileServer.createFileServer( new InetSocketAddress(8080), Path.of("/var/www"), SimpleFileServer.OutputLevel.VERBOSE);server.start();3. Code Snippets in JavaDoc - Java 18
Section titled “3. Code Snippets in JavaDoc - Java 18”Enhanced JavaDoc with @snippet tag for including code examples.
/** * A class for demonstrating snippets. * * {@snippet : * public class Example { * public static void main(String[] args) { * System.out.println("Hello"); // @highlight substring="println" * } * } * } * * {@snippet file="Example.java" region="main"} */public class DocumentationExample { // ...}Java 19 (September 2022)
Section titled “Java 19 (September 2022)”Virtual threads preview and structured concurrency.
1. Virtual Threads (Preview) - Java 19
Section titled “1. Virtual Threads (Preview) - Java 19”Lightweight threads for high-throughput concurrent applications.
// Creating virtual threadstry (var executor = Executors.newVirtualThreadPerTaskExecutor()) { // Submit 10,000 tasks easily for (int i = 0; i < 10_000; i++) { executor.submit(() -> { Thread.sleep(Duration.ofSeconds(1)); System.out.println("Task completed"); return i; }); }}
// Creating virtual threads directlyThread.startVirtualThread(() -> { System.out.println("Running in virtual thread");});
// Using Thread.BuilderThread.Builder builder = Thread.ofVirtual().name("worker-", 0);Thread virtualThread = builder.start(() -> { System.out.println("Virtual thread running");});2. Structured Concurrency (Preview) - Java 19
Section titled “2. Structured Concurrency (Preview) - Java 19”Simplifies error handling and cancellation in concurrent code.
import jdk.incubator.concurrent.StructuredTaskScope;
// Structured concurrency exampleString getUserInfo() throws Exception { try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { Future<String> user = scope.fork(() -> fetchUser()); Future<String> profile = scope.fork(() -> fetchProfile());
scope.join(); // Join both subtasks scope.throwIfFailed(); // Propagate any exception
return user.resultNow() + ": " + profile.resultNow(); }}3. Pattern Matching for switch (Third Preview) - Java 19
Section titled “3. Pattern Matching for switch (Third Preview) - Java 19”Further refinements to pattern matching for switch.
// Record patterns in switch (preview)record Point(int x, int y) {}
String classify(Object obj) { return switch (obj) { case Point(int x, int y) when x > 0 && y > 0 -> "Point in first quadrant"; case Point(int x, int y) when x < 0 && y > 0 -> "Point in second quadrant"; case String s -> "String: " + s; case null -> "Null object"; default -> "Unknown"; };}Java 20 (March 2023)
Section titled “Java 20 (March 2023)”Virtual threads and structured concurrency second preview.
1. Virtual Threads (Second Preview) - Java 20
Section titled “1. Virtual Threads (Second Preview) - Java 20”Enhanced virtual threads with better integration.
// Using virtual threads with ExecutorServicetry (var executor = Executors.newVirtualThreadPerTaskExecutor()) { List<Future<String>> futures = new ArrayList<>();
for (int i = 0; i < 1000; i++) { int taskId = i; futures.add(executor.submit(() -> { Thread.sleep(100); return "Task " + taskId + " completed"; })); }
// Wait for all tasks for (Future<String> future : futures) { System.out.println(future.get()); }}2. Scoped Values (Preview) - Java 20
Section titled “2. Scoped Values (Preview) - Java 20”Immutable data that can be safely shared within and across threads.
import jdk.incubator.concurrent.ScopedValue;
// Define scoped valueprivate static final ScopedValue<String> USERNAME = ScopedValue.newInstance();
// Set and use scoped valueScopedValue.where(USERNAME, "alice") .run(() -> { System.out.println(USERNAME.get()); // "alice" // Passed to child threads automatically });Java 21 (September 2023)
Section titled “Java 21 (September 2023)”Long-Term Support (LTS) release with major concurrency features.
1. Virtual Threads (Standard) - Java 21
Section titled “1. Virtual Threads (Standard) - Java 21”Virtual threads become a standard feature.
// Production-ready virtual threadsThreadFactory virtualThreadFactory = Thread.ofVirtual().factory();ExecutorService executor = Executors.newThreadPerTaskExecutor(virtualThreadFactory);
// Platform threads vs virtual threadsThread platformThread = Thread.ofPlatform() .name("platform-thread") .start(() -> System.out.println("Platform thread"));
Thread virtualThread = Thread.ofVirtual() .name("virtual-thread") .start(() -> System.out.println("Virtual thread"));
// CharacteristicsSystem.out.println("Virtual: " + virtualThread.isVirtual()); // trueSystem.out.println("Daemon: " + virtualThread.isDaemon()); // true2. Structured Concurrency (Standard) - Java 21
Section titled “2. Structured Concurrency (Standard) - Java 21”Structured concurrency becomes a standard feature.
import java.util.concurrent.StructuredTaskScope;
Response handle() throws ExecutionException, InterruptedException { try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { Future<String> user = scope.fork(() -> findUser()); Future<Integer> order = scope.fork(() -> fetchOrder());
scope.join(); // Wait for both scope.throwIfFailed(); // Throw if any failed
return new Response(user.resultNow(), order.resultNow()); }}
// Different shutdown policiestry (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) { scope.fork(() -> fetchFromSource1()); scope.fork(() -> fetchFromSource2()); scope.fork(() -> fetchFromSource3());
scope.join(); String result = scope.result(); // First successful result}3. Pattern Matching for switch (Standard) - Java 21
Section titled “3. Pattern Matching for switch (Standard) - Java 21”Pattern matching for switch becomes a standard feature.
// Exhaustive patterns with sealed hierarchiessealed interface Shape permits Circle, Rectangle, Triangle { double area();}
record Circle(double radius) implements Shape { public double area() { return Math.PI * radius * radius; }}
record Rectangle(double width, double height) implements Shape { public double area() { return width * height; }}
record Triangle(double base, double height) implements Shape { public double area() { return 0.5 * base * height; }}
String describe(Shape s) { return switch (s) { case Circle c -> "Circle with area " + c.area(); case Rectangle r -> "Rectangle with area " + r.area(); case Triangle t -> "Triangle with area " + t.area(); // No default needed - compiler knows all cases covered };}4. Record Patterns - Java 21
Section titled “4. Record Patterns - Java 21”Deconstruct record values directly in patterns.
record Point(int x, int y) {}record Line(Point start, Point end) {}
// Nested record patternsdouble length(Object obj) { return switch (obj) { case Point(int x, int y) -> Math.sqrt(x * x + y * y); case Line(Point(var x1, var y1), Point(var x2, var y2)) -> Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); default -> 0.0; };}
// Usage with instanceofif (obj instanceof Line(Point p1, Point p2)) { System.out.println("Line from " + p1 + " to " + p2);}Java 22 (March 2024)
Section titled “Java 22 (March 2024)”Adds string templates and unnamed patterns.
1. String Templates (Preview) - Java 22
Section titled “1. String Templates (Preview) - Java 22”Interpolates values into strings with validation.
// STR template processor (implicit import)String name = "Alice";int age = 30;
String message = STR."Hello \{name}, you are \{age} years old";// Result: "Hello Alice, you are 30 years old"
// FMT for formatted stringsdouble price = 19.99;String formatted = FMT."Price: %8.2f\{price}";// Result: "Price: 19.99"
// Custom template processorsvar INTER = StringTemplate.Processor.of( (StringTemplate st) -> st.interpolate().toUpperCase());
String shout = INTER."Important: \{name}";// Result: "IMPORTANT: ALICE"2. Unnamed Patterns and Variables - Java 22
Section titled “2. Unnamed Patterns and Variables - Java 22”Use underscore for unused patterns and variables.
// Unnamed pattern variableif (obj instanceof Point(_, int y)) { // Don't care about x System.out.println("Y coordinate: " + y);}
// Unnamed variabletry { int _ = Integer.parseInt("123"); // Result not needed} catch (NumberFormatException _) { // Exception not needed System.out.println("Invalid number");}
// In for loopsfor (int i = 0, _ = getInitialCount(); i < 10; i++) { System.out.println(i); // Don't need the initial count}
// Multiple unnamedrecord Triple(Object a, Object b, Object c) {}
Triple triple = new Triple("A", "B", "C");if (triple instanceof Triple(_, String b, _)) { System.out.println("Middle is: " + b); // "B"}Java 23 (September 2024)
Section titled “Java 23 (September 2024)”Latest features including primitive types in patterns.
1. Primitive Types in Patterns - Java 23
Section titled “1. Primitive Types in Patterns - Java 23”Pattern matching for primitive values.
// Pattern matching with primitivesObject obj = 42;
if (obj instanceof int i) { System.out.println("It's an int: " + i);}
// In switch expressionsString describeNumber(Object n) { return switch (n) { case byte b -> "tiny number: " + b; case short s -> "small number: " + s; case int i -> "integer: " + i; case long l -> "big integer: " + l; case float f -> "floating point: " + f; case double d -> "double precision: " + d; default -> "not a number"; };}2. Stream Gatherers - Java 23
Section titled “2. Stream Gatherers - Java 23”Custom intermediate operations for streams.
// Custom stream operationsList<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);
// Built-in gatherersList<List<Integer>> windows = numbers.stream() .gather(Gatherers.windowSliding(3)) .toList();// Result: [[1,2,3], [2,3,4], [3,4,5], [4,5,6]]
// Custom gathererGatherer<Integer, ?, Integer> runningMax = Gatherer.of( () -> new int[]{Integer.MIN_VALUE}, (state, element, downstream) -> { state[0] = Math.max(state[0], element); downstream.push(state[0]); return true; });
List<Integer> maxSoFar = numbers.stream() .gather(runningMax) .toList();// Result: [1, 2, 3, 4, 5, 6]Java 24 & 25 (Future Releases)
Section titled “Java 24 & 25 (Future Releases)”Upcoming features (subject to change).
Expected Features:
Section titled “Expected Features:”- Value Objects - Immutable identity-less objects
- Enhanced Generics - Better generic type inference
- Foreign Function & Memory API - Final version
- Vector API - For SIMD operations
- Project Loom - Continued concurrency improvements
Summary of Key Changes by Version
Section titled “Summary of Key Changes by Version”| Version | Year | Type | Key Features |
|---|---|---|---|
| 9 | 2017 | Major | Modules, JShell, Factory Collections |
| 10 | 2018 | Feature | Local variable type inference (var) |
| 11 | 2018 | LTS | HTTP Client, Launch single-file programs |
| 12 | 2019 | Feature | Switch expressions (preview), Teeing collector |
| 13 | 2019 | Feature | Text blocks (preview), Switch expressions enhanced |
| 14 | 2020 | Feature | Records (preview), Pattern matching instanceof |
| 15 | 2020 | Feature | Text blocks (standard), Sealed classes (preview) |
| 16 | 2021 | Feature | Records (standard), Pattern matching (standard) |
| 17 | 2021 | LTS | Sealed classes (standard), Pattern matching switch |
| 18 | 2022 | Feature | UTF-8 default, Simple web server |
| 19 | 2022 | Feature | Virtual threads (preview), Structured concurrency |
| 20 | 2023 | Feature | Virtual threads (2nd preview), Scoped values |
| 21 | 2023 | LTS | Virtual threads (standard), Record patterns |
| 22 | 2024 | Feature | String templates, Unnamed patterns |
| 23 | 2024 | Feature | Primitive patterns, Stream gatherers |