Skillversitas

Modern Java Features

Java continues to evolve with new features every 6 months. The latest LTS versions — Java 17 (2021) and Java 21 (2023) — bring many significant changes that make Java more concise, expressive, and performant. This chapter covers the modern features every Java developer today should know.

Sealed Classes (Java 17) restrict which classes can inherit. Records (Java 16) provide concise data classes. Pattern Matching instanceof (Java 16) combines type checking and casting. Switch Expressions (Java 14) eliminate fall-through bugs. Text Blocks (Java 15) make multi-line strings easy.

Virtual Threads (Java 21) bring lightweight threads like Go/Kotlin coroutines. Sequenced Collections (Java 21) add methods for ordered collections. Record Patterns (Java 21) allow deconstructing records in pattern matching. String Templates (Preview) make string interpolation easy.

Features by Version:

Version Main Features
Java 14 Switch expressions, helpful NullPointerExceptions
Java 15 Text blocks, hidden classes
Java 16 Records, pattern matching instanceof
Java 17 (LTS) Sealed classes, pattern matching switch
Java 21 (LTS) Virtual threads, sequenced collections, record patterns

Code Example

public class ModernFeatures {

    // Sealed classes (Java 17)
    sealed 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; }
    }

    non-sealed class Triangle implements Shape {
        double base, height;
        Triangle(double a, double t) { this.base = a; this.height = t; }
        public double area() { return 0.5 * base * height; }
    }

    // Pattern matching switch (Java 17+)
    static String describe(Shape shape) {
        return switch (shape) {
            case Circle c    -> "Circle r=" + c.radius();
            case Rectangle r -> "Square " + r.width() + "x" + r.height();
            case Triangle t  -> "Segitiga";
            // No default needed — the compiler knows all cases are covered
        };
    }

    // Record patterns (Java 21)
    static double calculateArea(Shape shape) {
        return switch (shape) {
            case Circle(var r)          -> Math.PI * r * r;
            case Rectangle(var w, var h) -> w * h;
            case Triangle(var a, var t) -> 0.5 * a * t;
        };
    }

    public static void main(String[] args) {
        Shape[] shapes = {
            new Circle(5),
            new Rectangle(4, 6),
            new Triangle(3, 8)
        };

        for (Shape s : shapes) {
            System.out.println(describe(s) + " | Area: " +
                String.format("%.2f", s.area()));
        }

        // Text blocks (Java 15+)
        String json = """
                {
                    "name": "John",
                    "age": 25,
                    "active": true
                }
                """;
        System.out.println(json);

        // Pattern matching instanceof
        Object obj = "Hello Java 21";
        if (obj instanceof String s && s.length() > 5) {
            System.out.println("Long string: " + s.toUpperCase());
        }
    }
}

Code Explanation

  1. Sealed classes: sealed interface Shape permits Circle, Rectangle, Triangle — only these classes may implement Shape. The compiler can check exhaustiveness.
  2. Record patterns: case Circle(var r) automatically deconstructs the record and captures the field into a local variable.
  3. Switch expressions: no break or default needed — the compiler knows all cases are covered (exhaustiveness check).
  4. Pattern matching instanceof: obj instanceof String s && s.length() > 5 — checks the type and assigns it to the variable s in a single expression.
  5. Text blocks: """...""" for multi-line strings — no escape characters or concatenation needed.

Everyday Example

Virtual threads for a parallel web scraper:

import java.net.URI;
import java.net.http.*;
import java.time.Duration;
import java.util.List;

public class WebScraper {
    public static void main(String[] args) throws Exception {
        List<String> urls = List.of(
            "https://jsonplaceholder.typicode.com/posts/1",
            "https://jsonplaceholder.typicode.com/posts/2",
            "https://jsonplaceholder.typicode.com/posts/3"
        );

        HttpClient client = HttpClient.newHttpClient();

        // Virtual threads — can create thousands of them!
        for (String url : urls) {
            Thread.startVirtualThread(() -> {
                try {
                    HttpRequest req = HttpRequest.newBuilder()
                        .uri(URI.create(url)).build();
                    HttpResponse<String> resp = client.send(req,
                        HttpResponse.BodyHandlers.ofString());
                    System.out.println(url + " → " + resp.statusCode());
                } catch (Exception e) {
                    System.err.println("Error: " + url);
                }
            });
        }

        Thread.sleep(5000); // wait for completion
    }
}

Summary

Modern Java features make the language far more productive and modern. Records, sealed classes, and pattern matching reduce boilerplate. Virtual threads change the way you write concurrent code. Upgrade to Java 21 to get all the latest features and better performance.