Skip to content

Java LTS Features Guide (Java 11, 17, 21, and 25)

This guide covers the major features introduced in Java 11, Java 17, Java 21, and Java 25 LTS releases, along with a detailed explanation of Virtual Threads and their differences from Platform Threads.


Java 11, released in 2018, is a Long-Term Support (LTS) release focused on productivity, performance, and modern APIs.

Java 11 introduced several useful methods to the String class.

  • isBlank()
  • lines()
  • strip()
  • stripLeading()
  • stripTrailing()
  • repeat(int count)
System.out.println(" ".isBlank());
System.out.println("Hello".repeat(3));
System.out.println(" Java ".strip());

Simplified file handling.

Path path = Files.writeString(Paths.get("file.txt"), "Hello");
String content = Files.readString(path);

A modern replacement for HttpURLConnection.

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com"))
.build();
HttpResponse<String> response =
client.send(request,
HttpResponse.BodyHandlers.ofString());

(var x, var y) -> x + y

Useful when applying annotations to lambda parameters.


Removed modules include:

  • java.xml.bind
  • java.xml.ws
  • CORBA

  • Nashorn JavaScript Engine (deprecated)
  • Pack200 tools removed

Improved encryption performance and security.


Terminal window
java Hello.java

No separate javac step is required.


Improves access between nested classes.


  • Improved G1 Garbage Collector
  • Better memory utilization
  • Better performance

Available without commercial licensing.

Useful for:

  • Monitoring
  • Profiling
  • Performance analysis

Java 17 is an LTS release introducing several modern language enhancements.


Restrict which classes may extend another class.

public sealed class Vehicle
permits Car, Bike {
}
final class Car extends Vehicle {
}
final class Bike extends Vehicle {
}
  • Controlled inheritance
  • Better maintainability
  • Useful with pattern matching

if(obj instanceof String){
String s = (String) obj;
System.out.println(s.length());
}
if(obj instanceof String s){
System.out.println(s.length());
}

Reduce boilerplate for immutable data classes.

public record Employee(int id, String name) {
}

Automatically generates:

  • Constructor
  • Accessors
  • equals()
  • hashCode()
  • toString()

String result = switch(day){
case "MONDAY", "FRIDAY" -> "Busy";
case "SUNDAY" -> "Holiday";
default -> "Normal";
};

String json = """
{
"name":"John",
"age":30
}
""";

Internal JDK APIs are strongly encapsulated.


  • ZGC improvements
  • Shenandoah GC support

  • Better cryptography
  • Stronger random generators

9. Foreign Function & Memory API (Incubator)

Section titled “9. Foreign Function & Memory API (Incubator)”

Allows efficient interaction with native code.


Improved graphics rendering on macOS.


public record User(int id, String name) {}
public class Main {
public static void main(String[] args) {
User user = new User(1, "Abi");
String result = switch (user.name()) {
case "Abi" -> "Developer";
default -> "Unknown";
};
System.out.println(result);
}
}

Java 21 introduces Project Loom and major concurrency improvements.


The most significant Java 21 feature.

Traditional thread:

Thread thread = new Thread(() -> {
System.out.println("Platform Thread");
});
thread.start();

Virtual Thread:

Thread.startVirtualThread(() -> {
System.out.println("Virtual Thread");
});

static String check(Object obj) {
return switch (obj) {
case Integer i -> "Integer: " + i;
case String s -> "String: " + s;
default -> "Unknown";
};
}

record Person(String name, int age) {}
if(obj instanceof Person(String name, int age)){
System.out.println(name);
}

try (var scope =
new StructuredTaskScope.ShutdownOnFailure()) {
// execute tasks
}

Benefits:

  • Better error handling
  • Automatic cancellation
  • Cleaner concurrent programming

List<Integer> list = List.of(1,2,3);
System.out.println(list.getFirst());
System.out.println(list.getLast());

String name = "Abi";
String message = STR."Hello \{name}";

ScopedValue<String> USER = ScopedValue.newInstance();

  • Better cryptography
  • Improved TLS
  • Stronger key encapsulation

  • Faster startup
  • Better JVM optimizations
  • Improved garbage collection

Java 25 continues Project Loom and introduces additional language and JVM enhancements.


A safer replacement for ThreadLocal.

static final ScopedValue<String> USER =
ScopedValue.newInstance();
ScopedValue.where(USER, "Abirami")
.run(() -> {
System.out.println(USER.get());
});

Benefits:

  • Immutable
  • Faster
  • Virtual Thread friendly

void main() {
System.out.println("Hello");
}

No class declaration required.


Statements before super() are now allowed.

public Employee(String name) {
name = name.trim();
if(name.isEmpty())
throw new IllegalArgumentException();
super(name);
}

import module java.sql;

try (var scope =
new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> user =
scope.fork(() -> getUser());
Future<String> orders =
scope.fork(() -> getOrders());
scope.join();
return user.resultNow()
+ orders.resultNow();
}

if(obj instanceof int i){
System.out.println(i);
}

Supports:

  • PBKDF2
  • Argon2

Useful for password hashing and key generation.


Benefits:

  • Lower memory usage
  • Better cache utilization
  • Faster object access

  • Lower pause times
  • Better throughput
  • Faster reclamation

Adds:

  • Faster startup
  • Better warm-up
  • Ahead-of-Time optimizations

Useful for:

  • Spring Boot
  • Containers
  • Cloud-native applications

Version Major Features
Java 8 Lambda Expressions, Streams, Optional
Java 11 HTTP Client, String APIs, File APIs
Java 17 Records, Sealed Classes, Pattern Matching
Java 21 Virtual Threads, Structured Concurrency
Java 25 Scoped Values, Flexible Constructors, Compact Source Files

Virtual Threads are lightweight threads introduced as part of Project Loom.

Unlike traditional Java threads, Virtual Threads are managed by the JVM rather than being permanently mapped to operating system threads.

Their purpose is to allow Java applications to efficiently support millions of concurrent tasks.


Traditional Java uses Platform Threads.

1 Java Thread
1 OS Thread

Each OS thread consumes:

  • Stack memory (~1 MB)
  • Scheduling overhead
  • Expensive context switching

Creating large numbers of Platform Threads leads to excessive memory usage and poor scalability.


flowchart TD
    A["Java Thread"] --> B["Operating System Thread"]

flowchart TD
    A["1,000,000 Virtual Threads"]
    --> B["JVM Scheduler"]

    B --> C["20 Platform Threads"]

    C --> D["Operating System Threads"]

Thread thread = new Thread(() -> {
System.out.println("Platform Thread");
});
thread.start();

Thread.startVirtualThread(() -> {
System.out.println("Virtual Thread");
});

try (ExecutorService executor =
Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> processOrder());
}

Feature Platform Thread Virtual Thread
Managed By Operating System JVM
Memory ~1 MB Stack Much Smaller
Creation Cost High Very Low
Context Switching Operating System JVM Scheduler
Suitable For CPU-bound Tasks I/O-bound Tasks
Maximum Count Thousands Millions

Suppose an API receives 100,000 requests.

Each request:

  • Calls a database
  • Calls another microservice
  • Waits for network responses
Request 1 → Waiting DB
Request 2 → Waiting DB
Request 3 → Waiting DB

Eventually:

OS Thread Pool Full

New requests wait for an available thread.


Virtual Thread 1 → Waiting DB
Virtual Thread 2 → Waiting DB
Virtual Thread 3 → Waiting DB

When a Virtual Thread blocks on supported I/O:

  1. The JVM detaches (unmounts) the Virtual Thread from the Platform Thread.
  2. The Platform Thread immediately executes another Virtual Thread.
  3. When the I/O completes, the Virtual Thread is mounted again and resumes execution.

This dramatically improves scalability.


sequenceDiagram
    participant VT as Virtual Thread
    participant JVM as JVM Scheduler
    participant PT as Platform Thread
    participant DB as Database

    VT->>PT: Execute Task
    PT->>DB: Execute Query
    Note over VT: Virtual Thread is unmounted while waiting
    PT->>JVM: Platform Thread becomes available
    JVM->>PT: Schedule another Virtual Thread
    DB-->>PT: Response
    JVM->>VT: Remount Virtual Thread
    VT->>PT: Continue Execution

try (ExecutorService executor =
Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 100000; i++) {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(2));
return null;
});
}
}

Suitable for:

  • REST APIs
  • Spring Boot
  • Microservices
  • Database operations
  • Kafka consumers
  • HTTP calls
  • File I/O
  • Network operations

Avoid using Virtual Threads for purely CPU-intensive workloads.

for(int i = 0; i < 1_000_000_000; i++){
// Heavy computation
}

Virtual Threads improve scalability for blocking operations, not CPU throughput.


What are Virtual Threads and how are they different from Platform Threads?

Section titled “What are Virtual Threads and how are they different from Platform Threads?”

Virtual Threads are lightweight threads managed by the JVM, introduced as part of Project Loom.

Unlike Platform Threads, which are permanently mapped one-to-one with operating system threads, Virtual Threads are scheduled by the JVM onto a much smaller pool of Platform Threads.

When a Virtual Thread blocks on supported I/O operations, it is detached from the Platform Thread, allowing that Platform Thread to execute another Virtual Thread. Once the blocking operation completes, the Virtual Thread is remounted and continues execution.

This enables applications to handle millions of concurrent tasks while significantly reducing memory usage and thread management overhead.


Traditional Tomcat:

Tomcat Thread Pool (200 Threads)
200 Concurrent Requests

Virtual Threads:

Virtual Threads
100,000 Concurrent Requests

Note that while Virtual Threads increase request concurrency, downstream systems such as databases or external services can still become bottlenecks.


  • What are Records?
  • What are Sealed Classes?
  • Explain Pattern Matching.
  • What are Text Blocks?

  • What are Virtual Threads?
  • Explain Structured Concurrency.
  • What are Record Patterns?
  • What are Scoped Values?
  • What are Sequenced Collections?

  • What problem do Scoped Values solve?
  • Explain Flexible Constructor Bodies.
  • What are Compact Object Headers?
  • Explain Generational Shenandoah.
  • What improvements does Project Leyden bring?

  • What happens when a Virtual Thread blocks?
  • How are Virtual Threads scheduled?
  • What is thread pinning?
  • How do Virtual Threads differ from Reactive Programming?
  • Can Spring Boot use Virtual Threads?
  • Are Virtual Threads suitable for Kafka consumers?

  • Java 11 modernized the JDK with improved APIs, HTTP Client, and productivity enhancements.
  • Java 17 introduced modern language features such as Records, Sealed Classes, Pattern Matching, and Text Blocks.
  • Java 21 brought Project Loom into production with Virtual Threads and major concurrency improvements.
  • Java 25 continues Project Loom with Scoped Values, Flexible Constructor Bodies, Compact Source Files, and JVM optimizations.
  • Virtual Threads dramatically improve scalability for I/O-bound applications by allowing millions of lightweight concurrent tasks while reusing a small number of Platform Threads.