Skip to main content

Java 11 Features with Examples (and What Changed from Java 8)

What Java 11 added over Java 8, with runnable examples and real output from JDK 8 and JDK 11: var in lambdas, the new String methods, Files.readString, the standard HttpClient, single-file launch, nest-based access, and the Java EE and CORBA modules that were removed.

Java 11 (September 2018) was a long-term-support release, and for most teams it was the first LTS after Java 8. Compared with Java 8 it adds a small, practical set of language and library features, removes the Java EE and CORBA modules from the JDK, and includes everything that landed in Java 9 and 10 along the way. The features people actually use: var for local variables and lambda parameters, new String methods (isBlank, lines, strip, repeat), Files.readString, the standard java.net.http.HttpClient, and running a source file directly with java File.java. Every example below was compiled and run on a real JDK 11; the ones that break were run on JDK 8 and 11 side by side so you can see the real error.
AreaJava 8Java 11
Local variablesAlways write the typevar list = new ArrayList<String>(); (var arrived in Java 10, JEP 286)
Blank-string checks.trim().isEmpty()s.isBlank()
Read a file into a StringSeveral lines with Files.readAllBytes and a charsetFiles.readString(path)
HTTP clientHttpURLConnection or a libraryjava.net.http.HttpClient (JEP 321)
Run a one-file programjavac then javajava Hello.java (JEP 330)
JAXB, JAX-WS, CORBAInside the JDKRemoved (JEP 320); add them as dependencies
Tested against. Temurin 11.0.32.1 for every Java 11 demo, and Temurin 1.8.0_504 where a comparison with Java 8 is shown. The JEP list comes from the JDK 11 project page (general availability 25 September 2018). The runnable project is the java11-features module; ./run.sh regenerates every output quoted here.

What Java 11 added, what it removed, in one picture

Java 8 to Java 11 is not one release, it is three: 9, 10 and 11 all happened in between. Java 9 brought the module system (JEP 261), JShell (JEP 222) and the List.of/Set.of/Map.of factory methods (JEP 269); Java 10 brought var (JEP 286); Java 11 completed the set and cleaned house. The picture below groups what matters for a Java 8 developer.
Moving from Java 8 to Java 11 Added var (10), var in lambdas (11)String: isBlank, lines, strip, repeatFiles.readString / writeStringHttpClient, java File.java launch Removed (JEP 320) JAXB (javax.xml.bind)JAX-WS, JAF, javax.annotationCORBA, java.transactionAdd them back as dependencies Deprecated Nashorn JavaScript engine (335)Pack200 tools and API (336)Both later removed The red column is the one that breaks builds: code that compiled on 8 without any dependency can fail on 11.
Green is what you gain, red is what can break your build, amber is a warning about the future. The rest of this page takes the green items one at a time, then spends real time on the red one.

New String methods: isBlank, strip, lines, repeat

Java 11 added five handy String methods. The surprise is strip() versus the old trim(): trim() removes only characters up to U+0020 (space and control characters), while strip() removes anything Unicode considers whitespace. The demo pads a word with an EM SPACE (U+2003) to show the difference. Source: StringMethods.java.
String em = String.valueOf((char) 0x2003);   // EM SPACE
String padded = em + " hello " + em;
System.out.println("trim() length   : " + padded.trim().length());
System.out.println("strip() length  : " + padded.strip().length());
Output on JDK 11, from 01-string-methods.txt:
trim() length   : 9
strip() length  : 5
isBlank("  ")   : true   isEmpty: false
lines()         : [a, b, c]
repeat(3)       : ababab
stripLeading    : [x ]  stripTrailing: [  x]
trim() left all nine characters in place because the EM SPACE is above U+0020; strip() removed it and returned the five letters. isBlank() is true for a string of only whitespace, where isEmpty() is false. lines() splits on \n, \r and \r\n (the demo input contains both styles and still gives three lines) and returns a stream.
The same file on Java 8 does not compile. These methods do not exist before 11, and the compiler says so for each one (08-string-methods-on-8.txt):

src/StringMethods.java:9: error: cannot find symbol
symbol: method strip()

Files.readString and Path.of

Reading a small text file used to take a stream or a readAllBytes plus a charset. Java 11 adds Files.readString and Files.writeString (UTF-8 by default), and Path.of as a shorter way to build a path. Source: FilesDemo.java.
Files.writeString(p, "one\ntwo\nthree");
String s = Files.readString(p);
Path.of("a", "b", "c.txt");
read back       : one|two|three
Path.of         : a/b/c.txt
That is 02-files.txt. readString loads the whole file into memory, so it suits config files and fixtures, not multi-gigabyte logs; for those see the NIO.2 guide to streaming large files.

The standard HttpClient (JEP 321)

java.net.http.HttpClient was incubated in Java 9 and 10 and became standard in 11. It supports HTTP/1.1 and HTTP/2, synchronous and asynchronous calls, and a builder-style request. The demo starts a tiny local server (com.sun.net.httpserver) so that the output is stable and needs no internet. Source: HttpClientDemo.java.
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create(url)).GET().build();

HttpResponse<String> r = client.send(req, HttpResponse.BodyHandlers.ofString());
CompletableFuture<String> f = client.sendAsync(req, HttpResponse.BodyHandlers.ofString())
                                    .thenApply(HttpResponse::body);
sync            : 200 hello from server version=HTTP_1_1
header          : X-Demo=yes
async           : hello from server
Output from 03-http-client.txt. The client prefers HTTP/2 by default; this local server speaks plain HTTP/1.1, so the response reports HTTP_1_1. send blocks; sendAsync returns a CompletableFuture you can compose (see the CompletableFuture guide). Compared with HttpURLConnection, there is no connection-state juggling and no third-party dependency.

var in lambda parameters (JEP 323)

Java 10 allowed var for local variables; Java 11 allowed it in lambda parameters. It looks pointless ((var a, var b) -> a + b says nothing that (a, b) -> a + b did not), and for plain lambdas it is. The reason it exists is annotations: you cannot put an annotation on an inferred parameter, but you can on var. Source: VarLambda.java.
BiFunction<Integer, Integer, Integer> add = (var a, var b) -> a + b;
BiFunction<String, String, String> join = (@NonNull var a, @NonNull var b) -> a + "-" + b;
(var a, var b)  : 5
with annotation : x-y
04-var-lambda.txt has the output. One rule has a real compiler message: you cannot mix var and explicit types in the same parameter list (07-compile-errors.txt):
broken/VarWithoutLambda.java:6: error: invalid lambda parameter declaration
  (cannot mix 'var' and explicitly-typed parameters)

Run a source file directly (JEP 330)

With Java 11, java Hello.java compiles the file in memory and runs it, with no javac step and no .class file left behind. It is the quickest way to try something and is aimed at scripts and teaching. Source: SingleFile.java.
launched from source, java.version=11.0.32.1
That line is from 05-single-file.txt, produced by java src/SingleFile.java. The mode handles one file; multiple files need the normal compile step (later releases widened this).
Going deeper: nest-based access control (JEP 181)
Before 11, an inner class reading its outer class’s private field forced the compiler to generate a hidden access$000-style bridge method. Java 11 introduced nests: the JVM itself lets nest mates touch each other’s private members. The demo counts bridge methods on the outer class, expecting none. Source: NestMates.java; output in 06-nest-mates.txt:

nest host       : NestMates
inner can read  : 42
access$ methods on outer: 0
Practical effect: slightly smaller class files and reflection that finally agrees with the language (Class.getNestHost() reports the nest).

What broke: the Java EE and CORBA modules are gone (JEP 320)

This is the part of the Java 8 to 11 move that costs people an afternoon. Java 9 had already put java.xml.bind (JAXB), java.xml.ws (JAX-WS), java.activation, java.corba and friends behind a “deprecated for removal” flag. Java 11 deleted them (JEP 320). Code that used javax.xml.bind.JAXBContext compiled on Java 8 with no dependency at all, because the class shipped inside the JDK. On 11 it does not. The same file, compiled by both JDKs (JaxbRemoved.java):
$ javac broken/JaxbRemoved.java     (1.8.0_504)
(compiled cleanly)

$ javac broken/JaxbRemoved.java     (11.0.32.1)
broken/JaxbRemoved.java:1: error: package javax.xml.bind does not exist
import javax.xml.bind.JAXBContext;
broken/JaxbRemoved.java:6: error: cannot find symbol
2 errors
Transcript: 07-compile-errors.txt. The error is “package does not exist”, not “module removed”, which is why it looks like a typo at first. The fix is to add the library as an ordinary dependency. If you want to keep the javax.xml.bind package name, use Jakarta XML Binding 2.3.x (jakarta.xml.bind:jakarta.xml.bind-api plus a runtime such as org.glassfish.jaxb:jaxb-runtime); versions 3.0 and later use the jakarta.xml.bind package instead, so imports change too.
The same trap hides in other places. javax.annotation.PostConstruct (from java.xml.ws.annotation), javax.activation.DataSource, and javax.transaction are all in the removed set. If a Java 8 project fails to compile on 11 with “package javax.… does not exist”, check this list first.
Going deeper: every JEP in JDK 11
The JDK 11 project page lists these 17 JEPs:
  • 181 Nest-Based Access Control; 309 Dynamic Class-File Constants; 315 Improve Aarch64 Intrinsics
  • 318 Epsilon: A No-Op Garbage Collector (useful for allocation-free benchmarks)
  • 320 Remove the Java EE and CORBA Modules
  • 321 HTTP Client (Standard); 323 Local-Variable Syntax for Lambda Parameters; 330 Launch Single-File Source-Code Programs
  • 324 Key Agreement with Curve25519 and Curve448; 329 ChaCha20 and Poly1305; 332 TLS 1.3
  • 327 Unicode 10; 328 Flight Recorder; 331 Low-Overhead Heap Profiling
  • 333 ZGC: A Scalable Low-Latency Garbage Collector (Experimental)
  • 335 Deprecate the Nashorn JavaScript Engine; 336 Deprecate the Pack200 Tools and API
Flight Recorder is now the standard profiling tool for production; see Java Flight Recorder and Mission Control. If you are moving much further than 11, the Java 17 to Java 25 migration guide picks up where this page stops.

Common mistakes moving from Java 8 to 11

Assuming JAXB, JAX-WS or javax.annotation is still in the JDK
It is not. Add the Jakarta artifacts as dependencies, as shown above. This is the most common Java 8 to 11 build failure.
Using trim() to test for blank input
trim() ignores Unicode whitespace such as the EM SPACE, as the output above shows. Use isBlank() or strip() when the input may contain non-ASCII whitespace.
Using var where the type is not obvious
var is a readability tool, not a typing saver. var result = service.process(x); hides the type from the reader. Use it when the right-hand side already names the type.
Using readString on large files
It reads the whole file into one String. For large files, stream the lines instead.
Mixing var and explicit types in one lambda
The compiler rejects it with “invalid lambda parameter declaration”; use var for every parameter or for none.

Common interview questions on Java 11

What are the new features in Java 11 compared with Java 8?
Local-variable type inference with var (Java 10) including in lambda parameters (11), new String methods, Files.readString/writeString, the standard HTTP Client, single-file source launch, nest-based access control, TLS 1.3, Flight Recorder and the Epsilon and experimental ZGC collectors. The Java EE and CORBA modules were removed.
Difference between trim() and strip()?
trim() removes characters up to U+0020; strip() removes all Unicode whitespace (Character.isWhitespace). The EM SPACE demo above shows trim() leaving nine characters and strip() leaving five.
Difference between isEmpty() and isBlank()?
isEmpty() is true only for length zero. isBlank() is also true for a string of only whitespace: " ".isBlank() is true, " ".isEmpty() is false.
Why would you use var in a lambda parameter?
To attach annotations ((@NonNull var a, @NonNull var b) -> ...) while keeping the type inferred. Without annotations there is no benefit over omitting the types. All parameters in one lambda must either use var or none.
What did Java 11 remove?
The Java EE and CORBA modules (JEP 320): JAXB, JAX-WS, JAF, javax.annotation, CORBA and java.transaction. They are available as separate Jakarta artifacts.
How is the Java 11 HttpClient better than HttpURLConnection?
It supports HTTP/2, has a fluent builder API, provides both blocking send and non-blocking sendAsync (returning CompletableFuture), and is immutable and thread-safe once built.
How do you run a Java file without compiling it first?
java Hello.java (JEP 330). The source is compiled in memory; the first top-level class in the file must declare main.
What is nest-based access control?
A JVM-level concept (JEP 181) that lets classes in the same nest (an outer class and its inner classes) access each other’s private members without compiler-generated bridge methods.

FAQ

Is Java 11 an LTS release?
Yes. Java 11 (September 2018) was a long-term-support release. Newer LTS releases are covered in the Java 17 and Java 21 guides.
Why does my Java 8 code fail to compile on Java 11?
The most common cause is a missing javax.xml.bind, javax.annotation or similar package, because JEP 320 removed those modules. Add the matching Jakarta dependency.
Can I use var for fields and method parameters?
No. var works for local variables, for loop variables and lambda parameters only.
Does Java 11 have records and text blocks?
No. Text blocks and records arrived in Java 15 and 16 respectively; see the Java 17 features guide.
Should you target Java 11 today? Only for an existing codebase that is already there. For anything new, jump to a current LTS: the language gains from 12 to 17 (records, switch expressions, text blocks, sealed classes) are covered in the Java 17 guide, and the upgrade path is in the migration guide. If you are coming from the other direction, Java 8 features is the prerequisite.

Further reading

No Comments yet!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.