Java Tutorial
πŸ”

Java 11 Features

Java 11 Features

Java 11, released in September 2018, is the second Long-Term Support release after Java 8, and it is the version many teams actually migrated to directly, skipping the non-LTS releases in between entirely. Where Java 8 rewired how everyday code gets written, Java 11 is a smaller, more practical release β€” a handful of genuinely useful additions, a handful of new String methods, a modern HTTP client, the ability to run a single Java file without a separate compile step, alongside the removal of several modules that had been marked for deprecation since Java 9.

What Changed in Java 11?

FeatureWhat It Adds
New String methodsisBlank(), strip() / stripLeading() / stripTrailing(), lines(), repeat()
HttpClient APIA modern, standardized HTTP client in java.net.http, replacing the old HttpURLConnection
Single-file source launchRunning java Foo.java directly, with no separate javac step
var in lambda parametersExtends Java 10's var to lambda parameter lists specifically
Files.readString() / writeString()One-line reading and writing of an entire file as a String
Collection.toArray(IntFunction)A cleaner way to convert a collection into a correctly-typed array
Removed Java EE and CORBA modulesJAX-WS, JAXB, and other modules deprecated in Java 9 are fully removed
Epsilon and ZGC garbage collectorsA no-op GC for benchmarking, and an experimental low-pause-time collector

Why Java 11 Mattered

Java 11 is the version most teams actually landed on after Java 8 β€” Java 9 and 10 were six-month releases few production systems ever ran. Framing your answer around "the second LTS" rather than "the version after Java 10" reads as more accurate in an interview.

A check as simple as "is this string just whitespace" used to require chaining two separate calls together, with a subtle Unicode gap neither one actually closed.

1// File: BeforeJava11.java 2 3public class BeforeJava11 { 4 public static void main(String[] args) { 5 String input = " "; 6 7 // Checking for "blank" (whitespace-only) required trim() plus a 8 // length check - isBlank() did not exist yet 9 boolean isBlank = input.trim().isEmpty(); 10 11 System.out.println("Is blank: " + isBlank); 12 } 13}
Output:
Is blank: true

isBlank() expresses the same check directly, as a single, purpose-built method.

1// File: AfterJava11.java 2 3public class AfterJava11 { 4 public static void main(String[] args) { 5 String input = " "; 6 7 boolean isBlank = input.isBlank(); 8 9 System.out.println("Is blank: " + isBlank); 10 } 11}
Output:
Is blank: true

Both versions agree here, but isBlank() is also Unicode-aware in a way the trim()-based check never was β€” a distinction covered in more depth later in this article.

A Tour of Java 11's Core Features

New String Methods

isBlank(), strip() and its directional variants, lines(), and repeat() cover everyday text-handling tasks that previously needed a manual loop or a regular expression.

1// File: NewStringMethodsExample.java 2 3public class NewStringMethodsExample { 4 public static void main(String[] args) { 5 String withWhitespace = " Hello Java "; 6 String multiLine = "first\nsecond\nthird"; 7 8 System.out.println("isBlank on empty spaces: " + " ".isBlank()); 9 System.out.println("strip(): [" + withWhitespace.strip() + "]"); 10 System.out.println("stripLeading(): [" + withWhitespace.stripLeading() + "]"); 11 System.out.println("stripTrailing(): [" + withWhitespace.stripTrailing() + "]"); 12 System.out.println("repeat(3): " + "ab".repeat(3)); 13 multiLine.lines().forEach(line -> System.out.println("Line: " + line)); 14 } 15}
Output:
isBlank on empty spaces: true
strip(): [Hello Java]
stripLeading(): [Hello Java  ]
stripTrailing(): [  Hello Java]
repeat(3): ababab
Line: first
Line: second
Line: third

Files.readString() and writeString()

Reading or writing an entire small file as a String used to require wiring up a BufferedReader or InputStreamReader by hand β€” these two methods reduce that to one line each.

1// File: FilesReadWriteStringExample.java 2import java.nio.file.*; 3import java.io.IOException; 4 5public class FilesReadWriteStringExample { 6 public static void main(String[] args) throws IOException { 7 Path tempFile = Files.createTempFile("demo", ".txt"); 8 9 Files.writeString(tempFile, "Hello from Java 11"); 10 11 String content = Files.readString(tempFile); 12 System.out.println("File content: " + content); 13 14 Files.delete(tempFile); 15 } 16}
Output:
File content: Hello from Java 11

var in Lambda Parameters

Java 10 introduced var for local variables; Java 11 extended it specifically to lambda parameter lists, which matters because it allows annotations to be attached to a lambda parameter that implicit typing alone could never support. The full mechanics of var are covered in this series' dedicated article on local variable type inference.

1// File: VarInLambdaExample.java 2import java.util.function.*; 3 4public class VarInLambdaExample { 5 public static void main(String[] args) { 6 // var in a lambda parameter list allows annotations that plain 7 // implicit typing (first, second) would not allow to be attached 8 BinaryOperator<Integer> add = (var first, var second) -> first + second; 9 10 System.out.println(add.apply(4, 6)); 11 } 12}
Output:
10

The HttpClient API

java.net.http.HttpClient, standardized in Java 11 after an incubator period, replaces the old HttpURLConnection with a modern, fluent builder API and native support for HTTP/2. Building a request is fully self-contained and requires no network access; actually executing one requires calling send() or sendAsync() against a real endpoint.

1// File: HttpClientQuickLook.java 2import java.net.URI; 3import java.net.http.*; 4 5public class HttpClientQuickLook { 6 public static void main(String[] args) { 7 HttpClient client = HttpClient.newHttpClient(); 8 9 HttpRequest request = HttpRequest.newBuilder() 10 .uri(URI.create("https://api.example.com/status")) 11 .header("Accept", "application/json") 12 .GET() 13 .build(); 14 15 System.out.println("Request method: " + request.method()); 16 System.out.println("Request URI: " + request.uri()); 17 System.out.println("Accept header: " + request.headers().firstValue("Accept").orElse("none")); 18 19 // Actually executing the request needs network access: 20 // HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); 21 } 22}
Output:
Request method: GET
Request URI: https://api.example.com/status
Accept header: application/json

Running Java Programs Without Compiling

A single .java file can be run directly with the java launcher, skipping the separate javac step entirely β€” the source is compiled in memory and discarded, with no .class file ever written to disk.

Before Java 11 - two separate steps:

  javac Greet.java
  java Greet

After Java 11 - one step, no .class file ever written to disk:

  java Greet.java

This is meant specifically for quick scripts, small utilities, and trying something out β€” it only works for a program contained in a single source file.

Removed and Deprecated Features

Java 11 fully removed the Java EE and CORBA modules β€” javax.xml.bind (JAXB), javax.xml.ws (JAX-WS), and several others β€” that had been marked deprecated since Java 9. Any project still using them needs to add the equivalent library as an explicit dependency, since they no longer ship with the JDK at all. The Nashorn JavaScript engine, covered in this series' Java 8 article, was also deprecated in this release, ahead of its full removal in Java 15.

Real-World Example

A small internal tool needs to load a configuration file, skip its comment and blank lines, and prepare a request to validate one of its values against a remote service β€” a compact scenario using Files.readString(), the new String methods, and the HttpClient request-building API together.

1// File: ConfigLoader.java 2import java.nio.file.*; 3import java.util.*; 4import java.io.IOException; 5 6public class ConfigLoader { 7 8 public Map<String, String> loadConfig(Path configFile) throws IOException { 9 String content = Files.readString(configFile); 10 Map<String, String> config = new LinkedHashMap<>(); 11 12 content.lines() 13 .map(String::strip) 14 .filter(line -> !line.isBlank() && !line.startsWith("#")) 15 .forEach(line -> { 16 // limit=2 keeps everything after the first "=" intact as 17 // one value, so a value containing "=" is never truncated 18 String[] parts = line.split("=", 2); 19 config.put(parts[0].strip(), parts[1].strip()); 20 }); 21 22 return config; 23 } 24}
1// File: ConfigValidationClient.java 2import java.net.URI; 3import java.net.http.*; 4 5public class ConfigValidationClient { 6 private final HttpClient client = HttpClient.newHttpClient(); 7 8 public HttpRequest buildValidationRequest(String apiKey) { 9 return HttpRequest.newBuilder() 10 .uri(URI.create("https://api.example.com/validate-key")) 11 .header("Authorization", "Bearer " + apiKey) 12 .GET() 13 .build(); 14 15 // client.send(request, HttpResponse.BodyHandlers.ofString()) is what 16 // would actually execute this request against the live endpoint 17 } 18}
1// File: ConfigLoaderDemo.java 2import java.nio.file.*; 3import java.util.*; 4import java.net.http.*; 5 6public class ConfigLoaderDemo { 7 public static void main(String[] args) throws Exception { 8 Path configFile = Files.createTempFile("app-config", ".properties"); 9 String configContent = "# Application configuration\n" 10 + "api.key=demo-key-12345\n" 11 + "\n" 12 + "environment=production\n"; 13 Files.writeString(configFile, configContent); 14 15 ConfigLoader loader = new ConfigLoader(); 16 Map<String, String> config = loader.loadConfig(configFile); 17 18 System.out.println("Loaded config: " + config); 19 20 ConfigValidationClient validationClient = new ConfigValidationClient(); 21 HttpRequest request = validationClient.buildValidationRequest(config.get("api.key")); 22 23 System.out.println("Validation request URI: " + request.uri()); 24 System.out.println("Validation request method: " + request.method()); 25 26 Files.delete(configFile); 27 } 28}
Output:
Loaded config: {api.key=demo-key-12345, environment=production}
Validation request URI: https://api.example.com/validate-key
Validation request method: GET

A mistake that appears often in fresher pull requests is parsing a config file's raw lines directly, without stripping whitespace or skipping comment and blank lines first β€” a single trailing space on a key, or a stray blank line between entries, then quietly breaks a lookup that looks completely correct at a glance. Chaining strip(), isBlank(), and startsWith() together, exactly as ConfigLoader does here, is what keeps a hand-written parser from breaking on formatting a human reader would never even notice.

Combining Java 11 Features With Each Other

Files.readString() combined with String.lines() and the new whitespace methods is exactly the pattern this article's real-world example uses for parsing simple text-based configuration without a dedicated library. HttpRequest.newBuilder() composes naturally with java.time, since HttpClient and HttpRequest both support a timeout() configured with a Duration, tying directly back to the Date and Time API series. var in lambda parameters exists specifically to allow annotations on lambda parameters that implicit typing could never support, connecting directly to this Modern Java section's dedicated article on var.

Best Practices

Reach for Files.readString() and writeString() for small-to-medium text files instead of manually wiring up a BufferedReader or InputStreamReader, saving several lines of boilerplate for the common case.

Build one shared HttpClient instance and reuse it across requests rather than constructing a new one per call β€” HttpClient is designed to be reused and internally manages connection pooling.

Prefer strip() over trim() for new code, since strip() is Unicode-aware in a way trim() has never been, and reach for isBlank() instead of a manual trim().isEmpty() check.

Use single-file source launching for quick scripts and one-off utilities, but compile normally for anything that will actually ship β€” the feature exists specifically for the "try this quickly" workflow, not production deployment.

Common Mistakes

Assuming trim() and strip() are interchangeable overlooks that trim() only recognizes characters at or below code point U+0020, the old ASCII-era definition of whitespace, while strip() is fully Unicode-aware.

1// File: TrimVsStripMistake.java 2 3public class TrimVsStripMistake { 4 public static void main(String[] args) { 5 // U+2003 is the Unicode EM SPACE character - a real whitespace 6 // character that trim() does not recognize, since trim() only 7 // strips characters with code points at or below U+0020 8 String textWithUnicodeSpace = " Hello "; 9 10 System.out.println("trim() length: " + textWithUnicodeSpace.trim().length()); 11 System.out.println("strip() length: " + textWithUnicodeSpace.strip().length()); 12 } 13}
Output:
trim() length: 7
strip() length: 5

trim() leaves the Unicode space characters untouched, since they fall well outside the narrow range it recognizes, while strip() correctly removes them using Character.isWhitespace() internally.

Assuming Files.readString() adapts to whatever encoding a file happens to be written in overlooks that it always decodes using UTF-8 specifically, and throws rather than silently producing garbled text when the bytes do not form valid UTF-8.

1// File: ReadStringEncodingMistake.java 2import java.nio.file.*; 3import java.nio.charset.StandardCharsets; 4import java.io.IOException; 5 6public class ReadStringEncodingMistake { 7 public static void main(String[] args) throws IOException { 8 Path tempFile = Files.createTempFile("encoding-demo", ".txt"); 9 10 // Writing raw bytes using UTF-16 encoding instead of UTF-8 11 Files.write(tempFile, "Hello".getBytes(StandardCharsets.UTF_16)); 12 13 try { 14 // readString() always assumes UTF-8 - it does not detect or 15 // adapt to whatever encoding the file was actually written with 16 Files.readString(tempFile); 17 System.out.println("Never printed"); 18 } catch (IOException e) { 19 System.out.println("IOException - readString() expected UTF-8, but the file was written as UTF-16"); 20 } 21 22 // Reading the bytes back with the correct charset works as expected 23 String correct = new String(Files.readAllBytes(tempFile), StandardCharsets.UTF_16); 24 System.out.println("Correct read: " + correct); 25 26 Files.delete(tempFile); 27 } 28}
Output:
IOException - readString() expected UTF-8, but the file was written as UTF-16
Correct read: Hello

Assuming single-file source launching works for a program spread across several files is another quiet trap β€” the feature is specifically limited to one source file at a time, and a genuine multi-file program still needs a normal javac and java workflow, or a build tool.

Interview Questions

Q1. What are the major features introduced in Java 11?

New String methods including isBlank(), strip(), lines(), and repeat(), the standardized HttpClient API, single-file source-code launching, Files.readString() and writeString(), var in lambda parameters, and the removal of the deprecated Java EE and CORBA modules. Interviewers often follow up by asking which of these actually changed daily coding habits, which is usually the new String methods and HttpClient.

Q2. What is the difference between String.trim() and String.strip()?

trim() removes only characters with a code point at or below U+0020, the historical ASCII definition of whitespace. strip(), added in Java 11, uses Character.isWhitespace() internally and correctly recognizes the full range of Unicode whitespace characters, including ones like the EM SPACE that trim() simply does not see as whitespace at all. The nuance being tested here is whether you know strip() exists for a real Unicode-correctness reason, not just as a renamed trim().

Q3. What does Files.readString() assume about a file's encoding, and what happens if that assumption is wrong?

It always decodes using UTF-8, with no auto-detection of the file's actual encoding. If the file's bytes do not form valid UTF-8, the call throws an IOException rather than silently producing garbled or incorrect text β€” a deliberate design choice that surfaces the mismatch immediately instead of letting corrupted data flow further into an application. Product-based interviews often push further and ask what you would do for a file that genuinely isn't UTF-8, which is the moment to mention passing an explicit Charset to the overloaded method.

Q4. What is single-file source-code launching, and what is it actually intended for?

It lets a single .java file be run directly with java Foo.java, compiling the source in memory and discarding the result without ever writing a .class file to disk, skipping the separate javac step entirely. It is intended for quick scripts, small utilities, and trying something out β€” it explicitly does not support a program spread across multiple source files, which is exactly the boundary interviewers probe for.

Q5. How is the Java 11 HttpClient different from the older HttpURLConnection?

HttpClient provides a modern, fluent builder API for constructing requests, native support for HTTP/2, both synchronous (send()) and asynchronous (sendAsync()) execution, and a reusable client object designed for connection pooling. HttpURLConnection predates all of this, requires considerably more boilerplate for common tasks, and has no native HTTP/2 support at all. A senior interviewer is usually listening for whether you know HttpClient instances are meant to be reused, not created per request.

Q6. What modules were removed in Java 11, and why does that matter for anyone upgrading from Java 8?

The Java EE and CORBA modules β€” javax.xml.bind (JAXB), javax.xml.ws (JAX-WS), and several related ones β€” were fully removed after being deprecated in Java 9. Any codebase upgrading directly from Java 8 that relies on these packages will fail to compile or run on Java 11 until the equivalent library is added explicitly as a project dependency, since they no longer ship bundled with the JDK. This is a common service-based-company question precisely because so many teams hit it during a real Java 8 to 11 migration.

FAQs

Is Java 11 a Long-Term Support release?

Yes, Java 11 is the second LTS release after Java 8, receiving extended support well beyond the six-month cycle that applies to non-LTS versions like Java 9 and 10.

Do I need to call javac before running a single Java file?

No, as long as the program is contained in one source file β€” java Foo.java compiles and runs it directly in one step. A program spread across multiple files still needs a normal compile step.

Does HttpClient support asynchronous requests?

Yes. sendAsync() returns a CompletableFuture<HttpResponse<T>> immediately, letting the calling code continue without blocking while the request completes in the background, in contrast to send(), which blocks until the response arrives.

What is the difference between String.strip() and String.trim() in terms of Unicode support specifically?

trim() recognizes only ASCII whitespace at or below code point U+0020. strip() uses Character.isWhitespace(), which correctly handles the full set of Unicode space characters, making strip() the more correct choice for any text that might contain non-ASCII input.

Can Files.readString() handle very large files?

It reads the entire file into memory as a single String, so it is well suited to small and medium-sized text files but not appropriate for very large files, where a streaming approach like Files.lines() or a BufferedReader is the better choice to avoid loading everything into memory at once.

Is var in Java 11 a new feature, or does it come from an earlier version?

var itself was introduced in Java 10 for local variable type inference. Java 11 extended it specifically to lambda parameter lists, which is the one piece of var's story that is genuinely new in this release.

What replaced the Java EE modules that were removed in Java 11?

Nothing replaced them inside the JDK itself β€” projects that still need JAXB, JAX-WS, or similar functionality now add the equivalent library, such as the Eclipse or GlassFish implementations, as an explicit Maven or Gradle dependency rather than relying on it being bundled with the JDK.

Summary

Java 11 is a smaller, more practical release than Java 8 β€” new String methods that close a real Unicode gap, a modern HttpClient that finally replaces HttpURLConnection, one-line file reading and writing, and a genuinely convenient way to run a quick script without a separate compile step, alongside the cleanup of modules that had already been on notice since Java 9.

The habits worth carrying forward are reaching for strip() and isBlank() over their older, ASCII-only equivalents, remembering that Files.readString() always assumes UTF-8, and treating single-file source launching as a tool for quick iteration rather than anything approaching a production deployment strategy β€” exactly the discipline the configuration loader example in this article is built around.

What to Read Next