CoreJava Java9

Features of Java 9 – Complete Overview with Examples

Features of Java 9 – Complete Overview with Examples

Java 9 was released on September 21, 2017, and brought one of the biggest architectural changes in Java's history: the Java Platform Module System (JPMS). Beyond modules, Java 9 packed in over 90 JDK Enhancement Proposals (JEPs) covering the Stream API, collections factories, private interface methods, a new REPL tool, and much more.

This post covers the most important Java 9 features with concise code examples so you can quickly understand what changed and why it matters for your day-to-day development.

1. Java Platform Module System (Project Jigsaw)

The module system lets you explicitly declare which packages a module exposes and which other modules it depends on. This improves encapsulation, reduces startup time, and makes large applications easier to maintain.


// module-info.java (in the module root)
module com.java9r.app {
    requires java.sql;         // depends on the java.sql module
    exports com.java9r.model;  // exposes this package to other modules
}

Every JDK library is now a module. You can create lean runtime images that include only the modules your app needs using the jlink tool.

2. JShell – Interactive Java REPL

Java 9 introduced jshell, an interactive Read-Eval-Print Loop (REPL) tool. You can now test snippets of Java code without creating a class or method.


$ jshell
|  Welcome to JShell -- Version 9
|  For an introduction type: /help intro

jshell> int x = 10;
x ==> 10

jshell> x * x
$2 ==> 100

jshell> "Hello".toUpperCase()
$3 ==> "HELLO"

jshell> /exit

JShell is invaluable for quickly testing API behavior without the overhead of writing a full program.

3. Collection Factory Methods – List.of(), Set.of(), Map.of()

Java 9 added convenient static factory methods to create immutable collections in one line:


import java.util.List;
import java.util.Set;
import java.util.Map;

// Immutable List
List<String> fruits = List.of("Apple", "Mango", "Banana");

// Immutable Set (no duplicates allowed)
Set<Integer> numbers = Set.of(1, 2, 3, 4, 5);

// Immutable Map (up to 10 entries)
Map<String, Integer> scores = Map.of("Alice", 95, "Bob", 87, "Carol", 92);

// Immutable Map with more than 10 entries
Map<String, Integer> large = Map.ofEntries(
    Map.entry("Alice", 95),
    Map.entry("Bob",   87),
    Map.entry("Carol", 92)
);

System.out.println(fruits);  // [Apple, Mango, Banana]
System.out.println(scores);  // {Alice=95, Bob=87, Carol=92}

// These collections are immutable – this throws UnsupportedOperationException:
// fruits.add("Grape");

4. Stream API Enhancements

Java 9 added four new methods to the Stream API:


import java.util.List;
import java.util.stream.Stream;

// takeWhile() – take elements while condition is true, stop at first false
List<Integer> nums = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
nums.stream()
    .takeWhile(n -> n < 5)
    .forEach(System.out::println);  // 1 2 3 4

// dropWhile() – skip elements while condition is true, take the rest
nums.stream()
    .dropWhile(n -> n < 5)
    .forEach(System.out::println);  // 5 6 7 8 9 10

// Stream.iterate() with a predicate (like a for loop)
Stream.iterate(1, n -> n <= 10, n -> n + 1)
      .forEach(System.out::println);  // 1 to 10

// Stream.ofNullable() – avoids null checks
String value = null;
Stream.ofNullable(value).forEach(System.out::println);  // prints nothing (no NPE)

5. Private Methods in Interfaces

Before Java 9, interfaces could only have abstract methods and (since Java 8) default/static methods. Java 9 allows private methods in interfaces to share code between default methods without exposing it:


interface Logger {

    default void logInfo(String msg) {
        log("INFO", msg);    // calls private helper
    }

    default void logError(String msg) {
        log("ERROR", msg);   // reuses same private helper
    }

    // Private – not accessible outside the interface
    private void log(String level, String msg) {
        System.out.println("[" + level + "] " + msg);
    }
}

class AppLogger implements Logger {}

// Usage:
AppLogger logger = new AppLogger();
logger.logInfo("Application started");    // [INFO] Application started
logger.logError("File not found");        // [ERROR] File not found

6. Optional Enhancements


import java.util.Optional;

Optional<String> name = Optional.of("Java 9");

// ifPresentOrElse() – handle both present and empty cases
name.ifPresentOrElse(
    n -> System.out.println("Found: " + n),
    ()  -> System.out.println("Not found")
);
// Output: Found: Java 9

// or() – supply another Optional if empty
Optional<String> empty = Optional.empty();
Optional<String> result = empty.or(() -> Optional.of("Default"));
System.out.println(result.get());  // Default

// stream() – convert Optional to a Stream (0 or 1 elements)
name.stream().forEach(System.out::println);  // Java 9

7. Diamond Operator for Anonymous Classes

In Java 8, you could not use the diamond operator <> with anonymous inner classes. Java 9 removes this restriction:


// Java 8 – had to specify the type explicitly
Comparator<String> c = new Comparator<String>() {
    public int compare(String a, String b) { return a.compareTo(b); }
};

// Java 9 – diamond works with anonymous classes
Comparator<String> c = new Comparator<>() {
    public int compare(String a, String b) { return a.compareTo(b); }
};

8. HTTP/2 Client (Incubator)

Java 9 added a new HTTP client API under the jdk.incubator.http module that supports HTTP/2 and WebSocket. It was promoted to a standard API in Java 11 as java.net.http.


// Java 9 (incubator) – preview of the modern HTTP client
// jdk.incubator.http.HttpClient became java.net.http.HttpClient in Java 11
import jdk.incubator.http.HttpClient;
import jdk.incubator.http.HttpRequest;
import jdk.incubator.http.HttpResponse;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.example.com/data"))
        .GET()
        .build();

9. Process API Improvements


// Get information about the current process
ProcessHandle current = ProcessHandle.current();
System.out.println("PID: " + current.pid());
System.out.println("Command: " + current.info().command().orElse("unknown"));

// List all running processes
ProcessHandle.allProcesses()
    .filter(p -> p.info().command().isPresent())
    .limit(5)
    .forEach(p -> System.out.println(p.pid() + ": " + p.info().command().get()));

10. Compact Strings (Internal Improvement)

Java 9 changed the internal representation of String. Previously, strings were always stored as char[] (2 bytes per character). Now Java uses a byte[] with a flag: Latin-1 characters use 1 byte each, saving significant memory for typical English text. This is transparent to developers — no code changes needed.

Summary of Java 9 Features

Feature JEP Impact
Module SystemJEP 261Architecture, security
JShell REPLJEP 222Developer productivity
Collection factoriesJEP 269Cleaner code
Stream enhancementsJEP 269takeWhile/dropWhile
Private interface methodsJEP 213Cleaner default methods
Optional enhancements-ifPresentOrElse, or()
HTTP/2 client (incubator)JEP 110Modern HTTP support
Process APIJEP 102System process management
Compact StringsJEP 254Memory reduction

Conclusion

Java 9 marked a turning point for the Java platform. The module system, though requiring some migration effort for existing applications, makes large codebases significantly more maintainable. The collection factories, stream enhancements, and private interface methods are immediately useful in daily development. Upgrading to Java 9+ is worthwhile for any project that can afford the module migration effort, and understanding these features is essential for modern Java development in 2024 and beyond.

Topics: CoreJava Java9
← Newer Post Older Post →

Comments

https://www.blogger.com/comment/frame/6690124484600543990?po=745748762926320140&hl=en&saa=85391&origin=https://www.java9r.com