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
All Java 11 Features at a Glance
The language, library and platform changes in Java 11, plus what you gain from Java 9 and 10 when upgrading from Java 8.
New String Methods
isBlank, lines, strip and repeat.
Files.readString and writeString
Read or write a whole file in one line.
Standard HTTP Client
A modern, built-in client for HTTP/1.1 and HTTP/2.
var in Lambda Parameters
Use var in lambdas to add annotations and modifiers.
Collection, Predicate and Optional Additions
Predicate.not, toArray(IntFunction) and Optional.isEmpty.
Run Single-File Programs Without javac
java Hello.java compiles and runs in one step.
Nest-Based Access Control
Nested classes share private access in the JVM.
JVM and Platform Changes
New garbage collectors, Flight Recorder and removed modules.
Also New Since Java 8: Java 9 and 10
What you gain when upgrading from Java 8 to Java 11.
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 stringsstrip(),stripLeading(),stripTrailing()remove all Unicode whitespacelines()returns aStream<String>repeat(n)concatenates the string n times
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);
}
}
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
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 StringFiles.writeString(Path, CharSequence, OpenOption...)writes text- UTF-8 by default; a
Charsetoverload is available Path.ofis the modern alternative toPaths.get
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);
}
}
Java 11 makes file I/O simple. No more readers! Characters: 47 Same as Path.of: true
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
HttpClientand immutableHttpRequests BodyHandlersconvert responses to String, bytes, files or streamssendAsyncreturns aCompletableFuture- The example starts a tiny local server, so it runs without internet access
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);
}
}
Status: 200
Type: application/json
Body: {"message":"Hello from Java 11"}
Async: {"message":"Hello from Java 11"}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
varfor all parameters or none; mixing is not allowed - Main benefit: annotations such as
(@NonNull var s) -> ...
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);
}
}
add(3, 4) = 7 upper = [ASHA, RAVI, MEERA]
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 naturallytoArray(IntFunction)avoidsnew String[0]Optional.isEmpty()makes empty checks clearer
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());
}
}
Predicate.not: [java, spring, kafka] toArray: 3 elements, first = java Optional.isEmpty: true
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
.classfiles are written to disk - The first top-level class in the file must contain
main - Scripts can start with
#!/usr/bin/java --source 11
// 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.");
}
}
$ java HelloSingleFile.java Asha Hello, Asha! Run without javac.
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
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);
}
}
Inner reads outer: outer secret Outer reads inner: 42 Nest host: NestAccessDemo Are nestmates: true Nest members: 2
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
# 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
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,iteratewith a condition - Java 9:
Optional.ifPresentOrElse,or,stream - Java 10:
var,List.copyOf,Collectors.toUnmodifiableList
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);
}
}
[a, b, c] 3 2 [1, 2, 3] [1, 2, 4, 8, 16] ifPresentOrElse: empty var + copyOf: [a, b, c]
Beyond Java 11
Later releases kept modernising the language. These are the highlights up to the next long-term-support releases:
| Version | Key additions |
|---|---|
| Java 12–13 | Switch expressions and text blocks as previews |
| Java 14 | Switch expressions, helpful NullPointerException messages |
| Java 15 | Text blocks ("""), ZGC production-ready |
| Java 16 | Records 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 |