Released September 2018 · Long-term support

Java 11 Features

Java 11 was the first long-term-support release after Java 8. It added new String and Files methods, a standard HTTP Client, var in lambdas and single-file programs, and cleaned up the platform. Learn every major feature with clear explanations and runnable examples.

  • String MethodsisBlank, lines, strip, repeat
  • HTTP ClientModern, built-in, HTTP/2
  • Files APIreadString, writeString
  • java File.javaRun without javac
Feature 01

New String Methods

Java 11 added small but very handy methods to String. strip() is a Unicode-aware replacement for trim(), isBlank() checks for whitespace-only text, lines() splits text into a stream of lines, and repeat(n) builds repeated strings without a loop.

  • isBlank(): true for empty or whitespace-only strings
  • strip(), stripLeading(), stripTrailing() remove all Unicode whitespace
  • lines() returns a Stream<String>
  • repeat(n) concatenates the string n times
StringMethodsDemo.java
public class StringMethodsDemo {
    public static void main(String[] args) {
        String blank = "   \t ";
        System.out.println("isBlank():  " + blank.isBlank());
        System.out.println("isEmpty():  " + blank.isEmpty());

        String padded = "  Java 11  ";                  // Unicode spaces
        System.out.println("trim():     [" + padded.trim() + "]");
        System.out.println("strip():    [" + padded.strip() + "]");
        String hi = "  hi  ";
        System.out.println("stripLeading:  [" + hi.stripLeading() + "]");
        System.out.println("stripTrailing: [" + hi.stripTrailing() + "]");

        System.out.println("repeat(3):  " + "ab".repeat(3));

        String text = "line one\nline two\nline three";
        System.out.println("lines():    " + text.lines().count() + " lines");
        text.lines().map(String::toUpperCase).forEach(System.out::println);
    }
}
Output
isBlank():  true
isEmpty():  false
trim():     [  Java 11  ]
strip():    [Java 11]
stripLeading:  [hi  ]
stripTrailing: [  hi]
repeat(3):  ababab
lines():    3 lines
LINE ONE
LINE TWO
LINE THREE
Feature 02

Files.readString and writeString

Reading a small text file used to need a reader, a loop or a byte-array conversion. Java 11 added Files.readString(path) and Files.writeString(path, text), which use UTF-8 by default, and Path.of(...) as a convenient way to create paths.

  • Files.readString(Path) returns the file content as a String
  • Files.writeString(Path, CharSequence, OpenOption...) writes text
  • UTF-8 by default; a Charset overload is available
  • Path.of is the modern alternative to Paths.get
FilesDemo.java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class FilesDemo {
    public static void main(String[] args) throws IOException {
        Path file = Files.createTempFile("notes", ".txt");

        // Java 11: write and read a whole file as a String in one call
        Files.writeString(file,
                "Java 11 makes file I/O simple.\nNo more readers!");
        String content = Files.readString(file);

        System.out.println(content);
        System.out.println("Characters: " + content.length());
        Path same = Path.of(file.toString());       // Path.of is new in Java 11
        System.out.println("Same as Path.of: " + same.equals(file));
        Files.delete(file);
    }
}
Output
Java 11 makes file I/O simple.
No more readers!
Characters: 47
Same as Path.of: true
Feature 03

Standard HTTP Client

The java.net.http module, incubating since Java 9, became standard in Java 11. It replaces the old HttpURLConnection with a fluent API that supports HTTP/2, WebSockets, timeouts, and both synchronous (send) and asynchronous (sendAsync) requests.

  • Build a reusable HttpClient and immutable HttpRequests
  • BodyHandlers convert responses to String, bytes, files or streams
  • sendAsync returns a CompletableFuture
  • The example starts a tiny local server, so it runs without internet access
HttpClientDemo.java
import com.sun.net.httpserver.HttpServer;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;

public class HttpClientDemo {
    public static void main(String[] args) throws Exception {
        // A tiny local server so the example runs without internet access
        HttpServer server = HttpServer.create(new InetSocketAddress(0), 0);
        server.createContext("/hello", exchange -> {
            byte[] body = "{\"message\":\"Hello from Java 11\"}"
                    .getBytes(StandardCharsets.UTF_8);
            exchange.getResponseHeaders()
                    .add("Content-Type", "application/json");
            exchange.sendResponseHeaders(200, body.length);
            exchange.getResponseBody().write(body);
            exchange.close();
        });
        server.start();
        int port = server.getAddress().getPort();

        // The standard HTTP Client (java.net.http)
        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(5))
                .build();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("http://localhost:" + port + "/hello"))
                .GET()
                .build();

        HttpResponse<String> response =
                client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println("Status: " + response.statusCode());
        String type = response.headers()
                .firstValue("Content-Type").orElse("?");
        System.out.println("Type:   " + type);
        System.out.println("Body:   " + response.body());

        // Asynchronous version returns a CompletableFuture
        String async = client
                .sendAsync(request, HttpResponse.BodyHandlers.ofString())
                .thenApply(HttpResponse::body)
                .join();
        System.out.println("Async:  " + async);
        server.stop(0);
    }
}
Output
Status: 200
Type:   application/json
Body:   {"message":"Hello from Java 11"}
Async:  {"message":"Hello from Java 11"}
Feature 04

var in Lambda Parameters

Java 10 introduced var for local variables. Java 11 lets you use it for lambda parameters too. The types are still inferred, but writing var means you can add annotations or final, which implicitly typed parameters do not allow.

  • Syntax: (var a, var b) -> a + b
  • Use var for all parameters or none; mixing is not allowed
  • Main benefit: annotations such as (@NonNull var s) -> ...
VarLambdaDemo.java
import java.util.List;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

public class VarLambdaDemo {
    @interface NonNull { }

    public static void main(String[] args) {
        // Java 10: var for local variables
        var names = List.of("asha", "ravi", "meera");

        // Java 11: var in lambda parameters (allows annotations, modifiers)
        BiFunction<Integer, Integer, Integer> add = (var a, var b) -> a + b;
        var upper = names.stream()
                .map((@NonNull var s) -> s.toUpperCase())
                .collect(Collectors.toList());

        System.out.println("add(3, 4) = " + add.apply(3, 4));
        System.out.println("upper     = " + upper);
    }
}
Output
add(3, 4) = 7
upper     = [ASHA, RAVI, MEERA]
Feature 05

Collection, Predicate and Optional Additions

Several core APIs gained convenient methods in Java 11. Predicate.not negates a method reference in a stream filter, Collection.toArray(String[]::new) creates a correctly typed array, and Optional.isEmpty() is the opposite of isPresent().

  • filter(Predicate.not(String::isBlank)) reads naturally
  • toArray(IntFunction) avoids new String[0]
  • Optional.isEmpty() makes empty checks clearer
ApiAdditionsDemo.java
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class ApiAdditionsDemo {
    public static void main(String[] args) {
        List<String> words = List.of("java", "", "spring", " ", "kafka");

        // Predicate.not: negate a method reference
        List<String> nonBlank = words.stream()
                .filter(Predicate.not(String::isBlank))
                .collect(Collectors.toList());
        System.out.println("Predicate.not:   " + nonBlank);

        // Collection.toArray(IntFunction)
        String[] array = nonBlank.toArray(String[]::new);
        System.out.println("toArray:         " + array.length
                + " elements, first = " + array[0]);

        // Optional.isEmpty
        Optional<String> missing = Optional.empty();
        System.out.println("Optional.isEmpty: " + missing.isEmpty());
    }
}
Output
Predicate.not:   [java, spring, kafka]
toArray:         3 elements, first = java
Optional.isEmpty: true
Feature 06

Run Single-File Programs Without javac

Java 11 (JEP 330) lets you run a program stored in a single source file directly with the java launcher. The file is compiled in memory and executed, which is ideal for learning, small utilities and scripts. On Linux and macOS you can even add a shebang line.

  • Command: java HelloSingleFile.java [args]
  • No .class files are written to disk
  • The first top-level class in the file must contain main
  • Scripts can start with #!/usr/bin/java --source 11
HelloSingleFile.java
// Save as HelloSingleFile.java and run it directly, without javac:
//     java HelloSingleFile.java Asha
public class HelloSingleFile {
    public static void main(String[] args) {
        String name = args.length > 0 ? args[0] : "World";
        System.out.println("Hello, " + name + "! Run without javac.");
    }
}
Run it
$ java HelloSingleFile.java Asha
Hello, Asha! Run without javac.
Feature 07

Nest-Based Access Control

A class and its nested classes form a nest. Before Java 11, the compiler generated hidden bridge methods so nested classes could reach each other's private members. Java 11 (JEP 181) made the JVM aware of nests, removing those bridges and adding reflection methods such as getNestHost() and isNestmateOf().

  • Nestmates can access each other's private members directly
  • No synthetic accessor methods, so bytecode is smaller and cleaner
  • Reflection: getNestHost, getNestMembers, isNestmateOf
NestAccessDemo.java
public class NestAccessDemo {
    private String secret = "outer secret";

    class Inner {
        private int code = 42;
        // private access within the nest
        String readOuter() { return secret; }
    }

    public static void main(String[] args) {
        NestAccessDemo outer = new NestAccessDemo();
        Inner inner = outer.new Inner();
        System.out.println("Inner reads outer: " + inner.readOuter());
        System.out.println("Outer reads inner: " + inner.code);

        // Java 11 reflection API for nests
        Class<?> host = Inner.class.getNestHost();
        System.out.println("Nest host:      " + host.getSimpleName());
        boolean mates = NestAccessDemo.class.isNestmateOf(Inner.class);
        System.out.println("Are nestmates:  " + mates);
        int members = NestAccessDemo.class.getNestMembers().length;
        System.out.println("Nest members:   " + members);
    }
}
Output
Inner reads outer: outer secret
Outer reads inner: 42
Nest host:      NestAccessDemo
Are nestmates:  true
Nest members:   2
Feature 08

JVM and Platform Changes

Java 11 also changed the platform itself. It added the experimental low-latency ZGC and the no-op Epsilon garbage collector, open-sourced Java Flight Recorder, added TLS 1.3, and removed the Java EE and CORBA modules that had been deprecated in Java 9. Applications that use JAXB or JAX-WS must add them as libraries when upgrading.

  • ZGC and Epsilon GC (experimental in Java 11)
  • Java Flight Recorder and Mission Control are free in OpenJDK
  • TLS 1.3 support and new cryptographic algorithms (ChaCha20, Curve25519)
  • Java EE / CORBA modules removed; Nashorn deprecated
Commands and notes
# Garbage collectors added in Java 11 (experimental)
# ZGC: very low pause times
java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC App
# Epsilon: no-op GC for performance testing
java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC App

# Java Flight Recorder: now free and open source in OpenJDK 11
java -XX:StartFlightRecording=duration=60s,filename=app.jfr App

# Removed in Java 11 (add them as Maven/Gradle dependencies):
#   java.xml.ws (JAX-WS), java.xml.bind (JAXB), java.activation,
#   java.xml.ws.annotation, java.corba, java.transaction
# Also removed: Java applets and Java Web Start; JavaFX ships separately.
# Deprecated: the Nashorn JavaScript engine
Feature 09

Also New Since Java 8: Java 9 and 10

Java 11 is the first long-term-support release after Java 8, so upgrading also brings everything added in Java 9 and 10: immutable collection factories, new Stream and Optional methods, var for local variables, the module system and JShell.

  • Java 9: List.of, Set.of, Map.of, modules, JShell, private interface methods
  • Java 9: Stream.takeWhile, dropWhile, iterate with a condition
  • Java 9: Optional.ifPresentOrElse, or, stream
  • Java 10: var, List.copyOf, Collectors.toUnmodifiableList
Java9And10Demo.java
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Java9And10Demo {
    public static void main(String[] args) {
        // Java 9: immutable collection factories
        List<String> list = List.of("a", "b", "c");
        Set<Integer> set = Set.of(1, 2, 3);
        Map<String, Integer> map = Map.of("one", 1, "two", 2);
        System.out.println(list + " " + set.size() + " " + map.get("two"));

        // Java 9: new Stream methods
        System.out.println(Stream.of(1, 2, 3, 10, 4).takeWhile(n -> n < 5)
                .collect(Collectors.toList()));
        System.out.println(Stream.iterate(1, n -> n <= 16, n -> n * 2)
                .collect(Collectors.toList()));

        // Java 9: Optional.ifPresentOrElse and or()
        Optional.empty().ifPresentOrElse(
                v -> System.out.println("value " + v),
                () -> System.out.println("ifPresentOrElse: empty"));

        // Java 10: var and unmodifiable copies
        var copy = List.copyOf(list);
        var joined = copy.stream().collect(Collectors.toUnmodifiableList());
        System.out.println("var + copyOf: " + joined);
    }
}
Output
[a, b, c] 3 2
[1, 2, 3]
[1, 2, 4, 8, 16]
ifPresentOrElse: empty
var + copyOf: [a, b, c]
What Came Next

Beyond Java 11

Later releases kept modernising the language. These are the highlights up to the next long-term-support releases:

VersionKey additions
Java 12–13Switch expressions and text blocks as previews
Java 14Switch expressions, helpful NullPointerException messages
Java 15Text blocks ("""), ZGC production-ready
Java 16Records and pattern matching for instanceof
Java 17 (LTS)Sealed classes, new random number generators
Java 21 (LTS)Virtual threads, record patterns, pattern matching for switch