Skip to content
Java modern java 6 min read

Java 11 LTS Features

Java 11, released in September 2018, is the first long-term support (LTS) release after Java 8. It brings a solid mix of quality-of-life improvements to strings, files, lambdas, and HTTP — making everyday coding noticeably cleaner.

Note: Java 11 removed many deprecated APIs and the standalone JavaFX/Java EE modules. If you are migrating from Java 8, check for removed classes before upgrading.

New String Methods

Java 11 adds several helpful instance methods directly to String so you no longer need third-party helpers like Apache Commons or Guava for common tasks.

isBlank()

Returns true when the string is empty or contains only whitespace. Unlike isEmpty(), it understands Unicode whitespace.

public class StringIsBlank {
    public static void main(String[] args) {
        System.out.println("".isBlank());        // true
        System.out.println("  ".isBlank());      // true
        System.out.println(" hi ".isBlank());    // false
    }
}

Output:

true
true
false

strip(), stripLeading(), stripTrailing()

These are the Unicode-aware replacements for trim(). The old trim() only removes ASCII control characters (≤ U+0020), while strip() respects all Unicode whitespace defined by Character.isWhitespace().

public class StringStrip {
    public static void main(String[] args) {
        String s = "  Hello, Java 11!  ";
        System.out.println(s.strip());           // "Hello, Java 11!"
        System.out.println(s.stripLeading());    // "Hello, Java 11!  "
        System.out.println(s.stripTrailing());   // "  Hello, Java 11!"
    }
}

Output:

Hello, Java 11!
Hello, Java 11!  
  Hello, Java 11!

repeat(int)

Repeats a string a given number of times.

public class StringRepeat {
    public static void main(String[] args) {
        System.out.println("ha".repeat(3));     // hahaha
        System.out.println("-".repeat(20));     // --------------------
    }
}

Output:

hahaha
--------------------

lines()

Splits a string into a Stream<String> of lines, respecting \n, \r, and \r\n line endings. Great for processing multi-line text without split("\n") edge cases.

import java.util.stream.Stream;

public class StringLines {
    public static void main(String[] args) {
        String text = "Line 1\nLine 2\nLine 3";
        text.lines().forEach(System.out::println);
    }
}

Output:

Line 1
Line 2
Line 3

Tip: lines() is lazy — it returns a Stream rather than an eager List, so it works efficiently even on large strings.


var in Lambda Parameters

Java 10 introduced var for local variable type inference. Java 11 extends this to lambda parameters, letting you annotate them with annotations while still relying on type inference.

import java.util.List;
import java.util.stream.Collectors;

public class VarInLambda {
    public static void main(String[] args) {
        var names = List.of("alice", "bob", "charlie");

        // var lets you add annotations on lambda params (e.g., @Nonnull)
        var upper = names.stream()
            .map((@SuppressWarnings("unused") var name) -> name.toUpperCase())
            .collect(Collectors.toList());

        System.out.println(upper);
    }
}

Output:

[ALICE, BOB, CHARLIE]

Note: All parameters in a lambda must use var — you cannot mix var with explicit types or with the inferred (no-annotation) form within the same lambda.


New Files Utility Methods

java.nio.file.Files gains two new static methods that eliminate boilerplate when reading or writing whole files as strings.

import java.nio.file.Files;
import java.nio.file.Path;

public class FilesReadWrite {
    public static void main(String[] args) throws Exception {
        Path path = Path.of("hello.txt");

        // Write a string directly to a file
        Files.writeString(path, "Hello from Java 11!\nSecond line.");

        // Read the whole file back as a String
        String content = Files.readString(path);
        System.out.println(content);
    }
}

Output:

Hello from Java 11!
Second line.

Both methods use UTF-8 by default. An overload accepts a Charset if you need something else. These build on NIO.2 Path & Files introduced in Java 7.


The New HTTP Client (java.net.http)

The new HttpClient API — previewed in Java 9 and finalized in Java 11 — replaces the ancient HttpURLConnection. It supports HTTP/1.1 and HTTP/2, both synchronous and asynchronous requests, and WebSockets.

Synchronous GET

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpClientDemo {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://httpbin.org/get"))
            .GET()
            .build();

        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println("Status: " + response.statusCode());
        System.out.println("Body: " + response.body().substring(0, 60) + "...");
    }
}

Output:

Status: 200
Body: {
  "args": {}, 
  "headers": {
    "Accept": "*/*",...

Asynchronous POST

import java.net.URI;
import java.net.http.*;
import java.util.concurrent.CompletableFuture;

public class HttpClientAsync {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://httpbin.org/post"))
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString("{\"key\":\"value\"}"))
            .build();

        CompletableFuture<HttpResponse<String>> future =
            client.sendAsync(request, HttpResponse.BodyHandlers.ofString());

        future.thenAccept(resp -> System.out.println("Async status: " + resp.statusCode()))
              .join(); // wait for demo purposes
    }
}

Tip: HttpClient instances are thread-safe and intended to be reused across requests. Create one per application, not one per request.


Running Java Files Directly (Single-File Programs)

Java 11 lets you run a single .java source file with java without a separate javac compile step:

java HelloWorld.java

The JVM compiles and runs the file in memory. This is perfect for quick scripts and learning. The file must have only one class (or nested classes), and it cannot depend on other user-written .java files.

Note: The class inside the file does not need to match the file name for the single-file launcher (unlike normal compilation rules).


Nest-Based Access Control

Before Java 11, when an inner class accessed a private member of its outer class, the compiler quietly generated a package-private bridge method. This leaked implementation details and showed up in stack traces.

Java 11 introduces NestMates: the JVM understands the nest relationship directly, so inner classes can access each other’s private members without bridge methods.

public class Outer {
    private String secret = "hidden";

    class Inner {
        void reveal() {
            // Direct access — no bridge method in Java 11+
            System.out.println("Secret: " + secret);
        }
    }

    public static void main(String[] args) {
        new Outer().new Inner().reveal();
    }
}

Output:

Secret: hidden

You can inspect nest membership with the new Class methods: getNestHost() and getNestMembers().


Epsilon: No-Op Garbage Collector

Java 11 ships the Epsilon GC (-XX:+UseEpsilonGC) — a garbage collector that allocates memory but never collects it. When the heap is exhausted the JVM exits.

This sounds strange, but it is genuinely useful for:

  • Performance testing (eliminate GC pauses from benchmarks)
  • Short-lived batch jobs that fit in memory
  • Testing that an application’s own memory management is correct

Warning: Never use Epsilon GC in a production server that handles unbounded work — your application will crash with OutOfMemoryError.


ZGC (Experimental)

Java 11 also ships ZGC as an experimental low-latency collector (-XX:+UseZGC). It targets pause times under 10 ms regardless of heap size. ZGC became production-ready in Java 15 and gained further improvements in Java 21. See Garbage Collection Deep-Dive for the full picture.


Removed & Deprecated Features

Java 11 removed several long-deprecated APIs. The most impactful removals:

RemovedReplacement
java.xml.ws (JAX-WS)Jakarta EE / standalone dependency
java.xml.bind (JAXB)jakarta.xml.bind artifact
javafx.* modulesOpenJFX separate download
java.se.ee meta-moduleIndividual Jakarta EE jars
sun.misc.Unsafe.defineClassMethodHandles.Lookup.defineClass
Thread destroy() / stop(one-arg)Cooperative interruption

If you are migrating from Java 8, add the relevant Jakarta EE jars to your build tool (Maven/Gradle) to replace removed modules.


Under the Hood

String Compaction (Java 9+, still relevant in 11)

String since Java 9 uses a byte[] with a coder flag: Latin-1 strings (ISO 8859-1) use 1 byte per character; others use UTF-16 (2 bytes). Java 11’s new strip() / isBlank() methods are implemented to work correctly with both encodings, which is why they are not just thin wrappers around trim().

HttpClient Internals

HttpClient is built on Java’s NIO event loop. A single thread can manage many concurrent connections via selector-based I/O, and it automatically negotiates HTTP/2 multiplexing when the server supports it — multiple logical request/response streams share one TCP connection.

NestMate Bytecode

The NestHost and NestMembers class-file attributes (new in Java 11) encode the nest relationship directly. The JVM’s invokevirtual and getfield access checks are nest-aware, so no synthetic accessor methods appear in the .class file or in stack traces anymore.


Last updated June 13, 2026
Was this helpful?