Skip to content

Java 11 (September 2018)

Java 11 Status

Release Information

Release Date: September 25, 2018 End of Support: September 2026 Theme: Modernization & Convenience

Overview

Java 11 is the first LTS release after Java 8 and represents a major milestone in Java's modernization. It introduced several convenience features that reduce boilerplate and improve developer productivity.


Local Variable Type Inference (var)

Introduced in Java 10, refined in Java 11

Java 10 introduced var for local variables. Java 11 extended it to lambda parameters.

The Problem

Explicit type declarations were verbose, especially with generics.

Before/After

// Verbose type declarations
Map<String, List<Customer>> customersByCity =
    new HashMap<String, List<Customer>>();

BufferedReader reader =
    new BufferedReader(new FileReader("data.txt"));

// In lambdas - no annotations possible
list.stream()
    .map((String s) -> s.toUpperCase())
    .collect(Collectors.toList());
// Type inference reduces noise
var customersByCity = new HashMap<String, List<Customer>>();

var reader = new BufferedReader(new FileReader("data.txt"));

// In lambdas with annotations (Java 11)
list.stream()
    .map((@NotNull var s) -> s.toUpperCase())
    .collect(Collectors.toList());

When to Use var

Good Use Cases

// Complex generic types
var entries = map.entrySet();

// try-with-resources
try (var stream = Files.lines(path)) { }

// Loops
for (var item : collection) { }

Avoid When

// Type is not obvious
var result = process(); // What type is result?

// Primitive literals
var count = 0; // Is this int, long, short?

HTTP Client API

Interview Favorite

Know that this replaced the old HttpURLConnection and supports HTTP/2.

The Problem

Java had no standard HTTP client. Developers relied on Apache HttpClient or OkHttp.

Before/After

// Old HttpURLConnection - verbose and painful
URL url = new URL("https://api.example.com/users");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");

int responseCode = conn.getResponseCode();
if (responseCode == 200) {
    BufferedReader in = new BufferedReader(
        new InputStreamReader(conn.getInputStream()));
    String line;
    StringBuilder response = new StringBuilder();
    while ((line = in.readLine()) != null) {
        response.append(line);
    }
    in.close();
}
// Modern HTTP Client - clean and powerful
HttpClient client = HttpClient.newHttpClient();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com/users"))
    .header("Accept", "application/json")
    .GET()
    .build();

// Synchronous
HttpResponse<String> response = client.send(
    request,
    HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.body());

// Asynchronous
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
    .thenApply(HttpResponse::body)
    .thenAccept(System.out::println);

HTTP Client Features

Feature Description
HTTP/2 Native support, automatic fallback to HTTP/1.1
WebSocket Built-in WebSocket client
Async sendAsync() returns CompletableFuture
Body Handlers ofString(), ofByteArray(), ofFile(), ofInputStream()

POST Example

HttpRequest postRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com/users"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(
        """
        {"name": "John", "email": "john@example.com"}
        """
    ))
    .build();

New String Methods

Overview

Java 11 added several convenience methods to the String class.

Methods

// isBlank() - checks for empty or whitespace only
"".isBlank();        // true
"   ".isBlank();     // true
"\t\n".isBlank();    // true
"hello".isBlank();   // false

// Better than isEmpty() for user input validation
if (userInput.isBlank()) {
    throw new IllegalArgumentException("Input required");
}
// lines() - splits into stream of lines
String multiline = "Line 1\nLine 2\nLine 3";

multiline.lines()
    .map(String::trim)
    .filter(line -> !line.isEmpty())
    .forEach(System.out::println);

// Count non-empty lines
long count = text.lines()
    .filter(line -> !line.isBlank())
    .count();
// strip() vs trim() - Unicode aware
String text = "\u2000 Hello World \u2000";

text.trim();   // "\u2000 Hello World \u2000" (doesn't remove Unicode whitespace)
text.strip();  // "Hello World" (removes all Unicode whitespace)

// Variants
text.stripLeading();  // "Hello World \u2000"
text.stripTrailing(); // "\u2000 Hello World"
// repeat() - repeat string n times
String line = "-".repeat(50);
// "--------------------------------------------------"

String indent = "  ".repeat(depth);

// Build a simple table border
String border = "+" + "-".repeat(20) + "+";

Comparison Table

Method Purpose Example
isBlank() Check empty/whitespace " ".isBlank() → true
lines() Split by line breaks "a\nb".lines() → Stream
strip() Remove Unicode whitespace " hi ".strip() → "hi"
stripLeading() Remove leading whitespace " hi ".stripLeading() → "hi "
stripTrailing() Remove trailing whitespace " hi ".stripTrailing() → " hi"
repeat(n) Repeat n times "ab".repeat(3) → "ababab"

Files API Improvements

The Problem

Reading/writing entire files required multiple lines of boilerplate.

Before/After

// Reading a file
String content = new String(
    Files.readAllBytes(Paths.get("file.txt")),
    StandardCharsets.UTF_8
);

// Writing a file
Files.write(
    Paths.get("file.txt"),
    content.getBytes(StandardCharsets.UTF_8)
);

// Reading lines
List<String> lines = Files.readAllLines(
    Paths.get("file.txt"),
    StandardCharsets.UTF_8
);
// Reading a file - one line!
String content = Files.readString(Path.of("file.txt"));

// Writing a file - one line!
Files.writeString(Path.of("file.txt"), content);

// With options
Files.writeString(
    Path.of("log.txt"),
    "New log entry\n",
    StandardOpenOption.APPEND,
    StandardOpenOption.CREATE
);

Collection Factory Methods

Introduced in Java 9

While technically Java 9, these are essential knowledge for Java 11 developers.

Before/After

// Creating immutable list
List<String> list = Collections.unmodifiableList(
    Arrays.asList("a", "b", "c")
);

// Creating immutable set
Set<String> set = Collections.unmodifiableSet(
    new HashSet<>(Arrays.asList("a", "b", "c"))
);

// Creating immutable map
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map = Collections.unmodifiableMap(map);
// Immutable collections in one line
List<String> list = List.of("a", "b", "c");

Set<String> set = Set.of("a", "b", "c");

Map<String, Integer> map = Map.of(
    "a", 1,
    "b", 2,
    "c", 3
);

// For more than 10 entries
Map<String, Integer> largeMap = Map.ofEntries(
    Map.entry("a", 1),
    Map.entry("b", 2),
    // ... more entries
);

Optional Improvements

New Methods in Java 11

Optional<String> opt = Optional.of("value");

// isEmpty() - opposite of isPresent()
if (opt.isEmpty()) {
    // handle empty case
}

// or() - provide alternative Optional
Optional<String> result = findInCache()
    .or(() -> findInDatabase())
    .or(() -> Optional.of("default"));

// ifPresentOrElse() - handle both cases
opt.ifPresentOrElse(
    value -> System.out.println("Found: " + value),
    () -> System.out.println("Not found")
);

// stream() - convert to stream (0 or 1 element)
List<String> values = optionals.stream()
    .flatMap(Optional::stream)
    .collect(Collectors.toList());

Running Single-File Programs

Before/After

# Two steps required
javac HelloWorld.java
java HelloWorld
# Single command
java HelloWorld.java

# With arguments
java Script.java arg1 arg2

# Shebang support (Unix)
#!/usr/bin/java --source 11
public class Script {
    public static void main(String[] args) {
        System.out.println("Hello!");
    }
}

Quick Reference

// var
var list = new ArrayList<String>();
var map = Map.of("key", "value");

// HTTP Client
HttpClient.newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofString());

// String methods
" text ".strip();        // "text"
"text".isBlank();        // false
"line1\nline2".lines();  // Stream<String>
"-".repeat(10);          // "----------"

// Files
String content = Files.readString(Path.of("file.txt"));
Files.writeString(Path.of("file.txt"), content);

// Collections
List.of("a", "b", "c");
Set.of(1, 2, 3);
Map.of("key", "value");