
Java 11 Features – What’s New and How to Use Them
Java 11 represents a significant milestone in the Java ecosystem, being the first Long Term Support (LTS) release after Java 8. Released in September 2018, it brought substantial performance improvements, new language features, and important API enhancements that have made it the go-to choice for modern enterprise applications. This post will walk you through the most impactful Java 11 features, show you how to implement them in real-world scenarios, and help you understand why upgrading from Java 8 might be one of the best decisions for your applications.
String API Enhancements
Java 11 introduced several new methods to the String class that significantly reduce boilerplate code. These additions make string manipulation more intuitive and performance-oriented.
// isBlank() - checks if string is empty or contains only whitespace
String emptyString = " ";
System.out.println(emptyString.isBlank()); // true
System.out.println("Hello".isBlank()); // false
// lines() - returns stream of lines
String multiline = "Line 1\nLine 2\nLine 3";
multiline.lines()
.forEach(System.out::println);
// strip(), stripLeading(), stripTrailing() - Unicode-aware trimming
String unicode = " \u2000 Hello World \u2000 ";
System.out.println(unicode.strip()); // "Hello World"
System.out.println(unicode.stripLeading()); // "Hello World \u2000 "
// repeat() - repeats string n times
String repeated = "Java".repeat(3);
System.out.println(repeated); // "JavaJavaJava"
The performance difference between the new strip() methods and the legacy trim() is notable. While trim() only removes ASCII whitespace characters, strip() handles all Unicode whitespace characters and uses more efficient algorithms.
Method | Unicode Support | Performance | Use Case |
---|---|---|---|
trim() | ASCII only | Good | Legacy applications |
strip() | Full Unicode | Better | Modern internationalized apps |
Local Variable Syntax for Lambda Parameters
Java 11 extends the var keyword introduced in Java 10 to lambda expressions, enabling you to add annotations to lambda parameters while maintaining type inference.
// Before Java 11
Consumer consumer1 = (String s) -> System.out.println(s);
// Java 11 - using var with annotations
Consumer consumer2 = (@NonNull var s) -> {
System.out.println(s.toUpperCase());
};
// Real-world example with validation
List names = Arrays.asList("John", "Jane", "Bob");
names.stream()
.filter((@NonNull var name) -> name.length() > 3)
.forEach(System.out::println);
This feature is particularly useful when you need to add annotations like @NonNull, @Nullable, or custom validation annotations to lambda parameters without losing the benefits of type inference.
HTTP Client API
Java 11 standardized the HTTP Client API that was incubated in Java 9 and 10. This modern, fully-featured HTTP client supports HTTP/2, WebSocket, and provides both synchronous and asynchronous request handling.
import java.net.http.*;
import java.net.URI;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
// Creating an HTTP client
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(20))
.build();
// Synchronous GET request
HttpRequest getRequest = HttpRequest.newBuilder()
.uri(URI.create("https://api.github.com/users/octocat"))
.build();
HttpResponse getResponse = client.send(getRequest,
HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + getResponse.statusCode());
System.out.println("Body: " + getResponse.body());
// Asynchronous POST request
String json = "{\"name\":\"test\",\"job\":\"developer\"}";
HttpRequest postRequest = HttpRequest.newBuilder()
.uri(URI.create("https://reqres.in/api/users"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
CompletableFuture> asyncResponse =
client.sendAsync(postRequest, HttpResponse.BodyHandlers.ofString());
asyncResponse.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
Feature | Java 11 HTTP Client | Apache HttpClient | OkHttp |
---|---|---|---|
HTTP/2 Support | Yes | Yes | Yes |
WebSocket | Yes | No | Yes |
Reactive Streams | Yes | No | No |
Built-in | Yes | No | No |
File API Improvements
Java 11 enhanced the Files class with convenient methods for reading and writing files as strings, making file I/O operations much more concise.
import java.nio.file.*;
import java.io.IOException;
// Reading file as string
Path filePath = Paths.get("example.txt");
try {
String content = Files.readString(filePath);
System.out.println(content);
} catch (IOException e) {
e.printStackTrace();
}
// Writing string to file
String data = "Hello World\nFrom Java 11";
try {
Files.writeString(filePath, data);
// Append to file
Files.writeString(filePath, "\nAppended line",
StandardOpenOption.APPEND);
} catch (IOException e) {
e.printStackTrace();
}
// Working with different charsets
try {
String utf8Content = Files.readString(filePath, StandardCharsets.UTF_8);
Files.writeString(Paths.get("output.txt"), utf8Content,
StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
Collection to Array Method
The new toArray() method in Collection interface allows type-safe conversion to arrays with a more intuitive API.
import java.util.*;
List list = Arrays.asList("apple", "banana", "orange");
// Java 11 way - cleaner and type-safe
String[] array1 = list.toArray(String[]::new);
// Compare with Java 8 approach
String[] array2 = list.toArray(new String[0]);
// Real-world example with filtering
List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer[] evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList())
.toArray(Integer[]::new);
System.out.println(Arrays.toString(evenNumbers)); // [2, 4, 6, 8, 10]
Nest-Based Access Control
Java 11 introduced nest-based access control, improving the way nested classes access each other’s private members. This feature primarily affects the JVM internals and reduces the number of synthetic bridge methods.
public class OuterClass {
private String outerField = "outer";
class InnerClass {
private String innerField = "inner";
void accessOuter() {
// Direct access without synthetic methods in Java 11+
System.out.println(outerField);
}
}
void accessInner() {
InnerClass inner = new InnerClass();
// Direct access to private field
System.out.println(inner.innerField);
}
// Check if classes are nestmates
public static void main(String[] args) {
System.out.println(OuterClass.class.isNestmateOf(InnerClass.class)); // true
System.out.println(Arrays.toString(OuterClass.class.getNestMembers()));
}
}
Running Single-File Source Programs
Java 11 introduced the ability to run single Java source files directly without explicit compilation, making it easier for scripting and quick testing.
# Create a simple Java file
cat > Hello.java << EOF
public class Hello {
public static void main(String[] args) {
System.out.println("Hello from Java 11!");
if (args.length > 0) {
System.out.println("Arguments: " + String.join(", ", args));
}
}
}
EOF
# Run directly without javac
java Hello.java arg1 arg2 arg3
# You can also use shebang for Unix-like systems
cat > script.java << EOF
#!/usr/bin/java --source 11
public class Script {
public static void main(String[] args) {
System.out.println("Running as script!");
}
}
EOF
chmod +x script.java
./script.java
JVM and Performance Improvements
Java 11 includes several JVM improvements that enhance performance and reduce memory footprint:
- Epsilon Garbage Collector: A no-op garbage collector for performance testing
- ZGC (Experimental): Low-latency garbage collector for large heaps
- Dynamic Class-File Constants: Reduces memory usage and improves performance
- Improved G1 Garbage Collector: Better performance for mixed workloads
# Enable Epsilon GC for testing
java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC MyApp
# Enable ZGC (experimental in Java 11)
java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC MyApp
# G1GC tuning options
java -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=16m MyApp
Migration Considerations and Common Issues
When migrating from Java 8 to Java 11, you'll encounter several changes that require attention:
- Removed modules: Java EE and CORBA modules are no longer included
- JavaFX separation: JavaFX is now a separate download
- Deprecated features: Several APIs have been deprecated or removed
# Common migration issues and solutions
# 1. Missing Java EE modules - add dependencies
# For JAXB
javax.xml.bind
jaxb-api
2.3.1
# 2. JavaFX applications
# Add JavaFX as external dependency
org.openjfx
javafx-controls
11.0.2
# 3. Check for usage of removed APIs
# Use jdeps tool to analyze dependencies
jdeps --jdk-internals myapp.jar
Best Practices and Real-World Applications
Here are practical recommendations for adopting Java 11 features in production environments:
- HTTP Client: Replace third-party HTTP libraries for new projects to reduce dependencies
- String methods: Use strip() instead of trim() for better Unicode handling
- File I/O: Leverage new Files methods for configuration file handling
- Single-file execution: Great for DevOps scripts and automation tools
// Example: Configuration file processor using Java 11 features
import java.nio.file.*;
import java.util.stream.Collectors;
public class ConfigProcessor {
public static void processConfig(String filename) throws Exception {
Path configPath = Paths.get(filename);
// Read and process configuration
String content = Files.readString(configPath);
String processed = content.lines()
.filter(line -> !line.strip().isEmpty())
.filter(line -> !line.strip().startsWith("#"))
.map(String::strip)
.collect(Collectors.joining("\n"));
// Write processed config
Files.writeString(Paths.get("processed_" + filename), processed);
}
}
Performance benchmarks show that Java 11 applications typically see 10-15% better performance compared to Java 8, with significantly lower memory usage due to improved garbage collection and runtime optimizations. The combination of new language features and JVM improvements makes Java 11 an excellent choice for both new development and migration projects.
For comprehensive documentation on all Java 11 features, visit the official Oracle Java 11 documentation and the OpenJDK Java 11 project page.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.