Important Java 11 Features with Examples

In this detailed article , we will explore important Java 11 features with examples.

Introduction: Java 11 Features

Java 11 was released on September 25, 2018. It marked a significant release in the Java programming language and platform.The release of Java 11 brought several new features, improvements, and enhancements to the language and platform.

Let’s look into the important Java 11 features with examples.

Important Java 11 Features

Important Java 11 Features

Local-Variable Syntax for Lambda Parameters

Local-Variable Syntax for Lambda Parameters” is one the key Java 11 features . It allows you to use the var keyword to declare the types of parameters in lambda expressions.

Let’s first look into the “Old way” of declaring lambda parameters with explicit types:

import java.util.function.BiFunction;

public class LambdaParameterExample {
    public static void main(String[] args) {
        // Old way: Explicitly declaring types
        BiFunction<Integer, Integer, Integer> add = (Integer x, Integer y) -> x + y;
        System.out.println("Using explicit types: " + add.apply(5, 3));

In this code, we’re using the BiFunction functional interface to represent a lambda expression that takes two Integer parameters and returns an Integer result. The lambda parameters x and y are explicitly declared with their types as Integer.

Now, let’s write the same thing using Java 11 var keyword.

import java.util.function.BiFunction;

public class LambdaParameterExample {
    public static void main(String[] args) {
        // Old way: Explicitly declaring types
        BiFunction<Integer, Integer, Integer> addOld = (Integer x, Integer y) -> x + y;
        System.out.println("Using explicit types: " + addOld.apply(5, 3));

        // New way: Using var for lambda parameters
        BiFunction<Integer, Integer, Integer> addNew = (var x, var y) -> x + y;
        System.out.println("Using 'var' keyword: " + addNew.apply(5, 3));

In this “New way,” with the feature introduced in Java 11, we use the var keyword instead of explicitly declaring the types. Java infers the types of the lambda parameters based on the context and the expected types from the functional interface.

Asynchronous HTTP Client

Java 11 introduced a new, asynchronous HTTP client as a part of the package. It provides improved support for handling HTTP requests and responses, including asynchronous operations and HTTP/2 support. It as an alternative to the legacy HttpURLConnection. It provides a more flexible and intuitive way to work with HTTP requests and responses.

Here’s an example of using the asynchronous HTTP client introduced in Java 11 to make asynchronous HTTP requests:

import java.util.concurrent.CompletableFuture;

public class AsyncHttpClientExample {
    public static void main(String[] args) {
        HttpClient httpClient = HttpClient.newHttpClient();

        // Create an asynchronous HTTP request
        HttpRequest request = HttpRequest.newBuilder()

        // Send the asynchronous request and handle the response asynchronously
        CompletableFuture<HttpResponse<String>> responseFuture = httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());

        // Attach a callback to process the response when it's available
        responseFuture.thenApplyAsync(response -> {
            int statusCode = response.statusCode();
            String responseBody = response.body();
            System.out.println("Status Code: " + statusCode);
            System.out.println("Response Body:\n" + responseBody);
            return responseBody;
        }).join(); // Wait for the response processing to complete

        // Continue with other tasks...

In this example:

  1. We create an instance of HttpClient using HttpClient.newHttpClient().
  2. We create an HttpRequest object to specify the request details, including the URI.
  3. We use httpClient.sendAsync() to send the asynchronous HTTP request. The response is obtained as a CompletableFuture<HttpResponse<String>>.
  4. We use thenApplyAsync() to attach a callback that processes the response when it becomes available. The callback extracts the status code and response body and prints them.
  5. The join() method is used to wait for the asynchronous processing of the response to complete. This ensures that we don’t continue with other tasks before the response processing is done.

The asynchronous HTTP client in Java 11 provides a non-blocking way to perform HTTP requests and handle responses, making it suitable for scenarios where you want to avoid blocking the main thread while waiting for network operations.

Nest-Based Access Control

Nest-Based Access Control, introduced in Java 11, allows classes that are logically part of the same code entity to access each other’s private members without the need for explicit visibility modifiers. Here’s an example to demonstrate Nest-Based Access Control:

class Outer {
    private int outerPrivate = 10;

    class Inner {
        private int innerPrivate = 20;

        void accessOuterPrivate() {
            System.out.println("Accessing outer private: " + outerPrivate);

public class NestAccessExample {
    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = Inner();

        inner.accessOuterPrivate(); // Access outer private member from inner class

In this example:

  1. The Outer class contains a private field outerPrivate.
  2. The Inner class is nested within the Outer class and contains a private field innerPrivate.
  3. The Inner class defines a method accessOuterPrivate() that accesses the private field outerPrivate from the enclosing Outer class.

With Nest-Based Access Control, the Inner class can directly access the private outerPrivate member of the Outer class without requiring explicit getter methods or changing the visibility of the field.

Epsilon: A No-Op Garbage Collector

Java 11 introduced the Epsilon garbage collector, which is intended for scenarios where you want to disable garbage collection entirely.

The primary use case for the Epsilon garbage collector is performance testing and benchmarking. When running performance tests or benchmarks, memory allocation and deallocation can introduce noise in the measurements, affecting the accuracy of the results. By using Epsilon, developers can eliminate the overhead of garbage collection during tests, enabling more accurate performance analysis of other parts of the application.

Here’s a brief example of how to enable and use the Epsilon garbage collector:

java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC YourApplication

In this command, the -XX:+UnlockExperimentalVMOptions flag allows you to use experimental VM options, and the -XX:+UseEpsilonGC flag enables the Epsilon garbage collector.

Keep in mind that using Epsilon in production scenarios is not recommended, as it does not provide any memory reclamation and will lead to memory exhaustion if the application continuously allocates memory without releasing it.

Dynamic Class-File Constants

Dynamic Class-File Constants is a feature introduced in Java 11 that allows the Java Virtual Machine (JVM) to resolve constant values at runtime, enabling more flexible and efficient libraries. Here’s a brief example of how you might use dynamic class-file constants:

public class DynamicConstantsExample {
    public static void main(String[] args) {
        String dynamicMessage = ConstantsHolder.MESSAGE;


class ConstantsHolder {
    static {
        System.out.println("Initializing ConstantsHolder");

    public static final String MESSAGE = getDynamicMessage();

    private static String getDynamicMessage() {
        return "Hello, Dynamic Constants at " + System.currentTimeMillis();

In this example:

  1. The ConstantsHolder class contains a static initialization block that prints “Initializing ConstantsHolder” when the class is initialized.
  2. The MESSAGE constant is defined as public static final String, but its value is computed at runtime using the getDynamicMessage() method.
  3. The getDynamicMessage() method generates a dynamic message containing the current timestamp.
  4. In the DynamicConstantsExample class, we access the MESSAGE constant from ConstantsHolder and print its value.

When you run the DynamicConstantsExample class, you’ll observe that the output includes the dynamically generated message along with the timestamp, reflecting the runtime value of the constant:

Initializing ConstantsHolder
Hello, Dynamic Constants at [current timestamp]

Single-File Source-Code Programs

Java 11 allows you to run a single-file source-code program without explicitly compiling it. You can use the java command to run a .java file directly.

Here’s a simple example of a single-file source-code program:

public class HelloSingleFile {
    public static void main(String[] args) {
        System.out.println("Hello, Single-File Source-Code Programs!");

Save the above code in a file named Open a terminal, navigate to the directory containing the file, and run the program using the command:



Hello, Single-File Source-Code Programs!

It’s important to note that this feature is intended for short and simple programs. If your program becomes more complex or needs to be shared with others, it’s recommended to use traditional compilation and packaging methods.

Flight Recorder and Mission Control Open Sourced

Java Flight Recorder (JFR) and Java Mission Control (JMC) are tools introduced in Java 11 that provide developers with powerful capabilities for monitoring, profiling, and troubleshooting Java applications. They are designed to help developers optimize application performance, diagnose issues, and analyze the behavior of Java applications in real time.

Java Flight Recorder is a profiling and event collection framework built into the Java Virtual Machine (JVM). It collects detailed information about the runtime behavior of an application, including CPU usage, memory allocation, thread activity, garbage collection events, and more.

Java Mission Control(JMC) is a tool suite that provides a graphical interface for analyzing data collected by Java Flight Recorder. It offers a range of features to visualize, analyze, and optimize Java applications’ performance. JMC allows developers to monitor application behavior in real time and gather insights into the application’s resource usage, bottlenecks, and more.

Deprecating Java EE and CORBA Modules

Java EE (Enterprise Edition) and CORBA (Common Object Request Broker Architecture) modules were deprecated and subsequently removed from the Java SE platform starting with Java 11. This decision was part of Oracle’s efforts to simplify and modernize the Java platform and to align with the evolving needs of the Java community.

Improved Security and Performance in Java 11

Improvements in security and performance introduced in Java 11:

  1. TLS 1.3 Support: Added support for more secure and faster TLS 1.3 protocol.
  2. Enhanced Key Agreement: Added support for Curve25519 and Curve448 for secure key exchange.
  3. Security Enhancements: Improved cryptographic algorithms and security protocols.
  4. Single-File Programs: Run source-code programs without separate compilation for quicker testing.
  5. Performance Boosts: Optimized JVM startup times and memory usage.
  6. G1 Garbage Collector: Enhanced G1 collector for better performance and lower latency.
  7. ZGC and Epsilon: Introduced Z Garbage Collector and Epsilon GC for specialized memory management.
  8. JVM Improvements: New options for performance tuning and memory management.

Conclusion: Important Java 11 Features

In this comprehensive article, we explored the key Java 11 features with relevant examples. Hopefully, this will enable you to use these Java 11 features in your projects.

Leave a Reply

Your email address will not be published. Required fields are marked *