-
Notifications
You must be signed in to change notification settings - Fork 0
Java 9
Release Date: September 21, 2017 | Type: Standard (non-LTS) | Status:
⚠️ End of Life
Java 9's headline feature was Project Jigsaw — the Java Platform Module System (JPMS), the biggest structural change to the JDK since its inception. It also quietly shipped a huge set of Streams/Optional/Collections quality-of-life improvements.
flowchart LR
A[Monolithic JDK\npre-Java 9] -->|Project Jigsaw| B[Modular JDK\nJava 9+]
B --> C[java.base]
B --> D[java.sql]
B --> E[java.xml]
B --> F[Your App Module]
F -->|requires| C
F -->|requires| D
What: Group packages into named modules with explicit dependencies and exports — strong encapsulation at the JVM level, not just public/private.
// module-info.java
module com.myapp.orders {
requires java.sql;
requires com.myapp.common;
exports com.myapp.orders.api;
// com.myapp.orders.internal is NOT exported — truly hidden
}graph TD
OrdersModule["com.myapp.orders"] -->|requires| SqlModule["java.sql"]
OrdersModule -->|requires| CommonModule["com.myapp.common"]
OrdersModule -->|exports| API["com.myapp.orders.api"]
OrdersModule -.->|hidden| Internal["com.myapp.orders.internal"]
Why it matters: Before Java 9, any code on the classpath could reflectively access any internal class. Modules make encapsulation real, reduce the "classpath hell" of large applications, and let the JDK itself ship smaller runtime images via jlink.
# Build a custom minimal runtime with only the modules you need
jlink --module-path $JAVA_HOME/jmods:mods \
--add-modules com.myapp.orders \
--output custom-runtimeWhat: An interactive Read-Eval-Print Loop for Java, finally.
$ jshell
jshell> int x = 5
x ==> 5
jshell> x * 2
$2 ==> 10
jshell> List.of(1, 2, 3).stream().map(n -> n * n).forEach(System.out::println)
1
4
9Why it matters: Rapid prototyping and learning without the edit-compile-run cycle — great for testing a Stream pipeline or API idea in seconds.
What: Interfaces can now have private and private static methods to share code between default methods.
public interface ReportGenerator {
default String generatePdfReport(String data) {
return format(data, "PDF");
}
default String generateCsvReport(String data) {
return format(data, "CSV");
}
// Shared logic — not exposed to implementers
private String format(String data, String type) {
return "[" + type + "] " + data.trim().toUpperCase();
}
}// takeWhile() — take elements while condition is true, stop at first failure
Stream.of(1, 2, 3, 4, 1, 2)
.takeWhile(n -> n < 4)
.forEach(System.out::println); // 1, 2, 3
// dropWhile() — opposite: drop while true, then take the rest
Stream.of(1, 2, 3, 4, 1, 2)
.dropWhile(n -> n < 4)
.forEach(System.out::println); // 4, 1, 2
// iterate() with a predicate — bounded iteration, no need for limit()
Stream.iterate(1, n -> n < 100, n -> n * 2)
.forEach(System.out::println); // 1, 2, 4, 8, 16, 32, 64
// ofNullable() — a stream of 0 or 1 elements
Stream.ofNullable(getMaybeNull())
.forEach(System.out::println);flowchart LR
subgraph Source["Stream: 1, 2, 3, 4, 1, 2"]
direction LR
end
Source --> TW["takeWhile(n < 4)"]
Source --> DW["dropWhile(n < 4)"]
TW --> TWResult["1, 2, 3\n(stops at first failure)"]
DW --> DWResult["4, 1, 2\n(drops until first failure, keeps rest)"]
style TWResult fill:#d4f4dd,stroke:#22863a
style DWResult fill:#fff4e0,stroke:#cc8800
Optional<String> name = Optional.of("Neelu");
// ifPresentOrElse — handle both branches
name.ifPresentOrElse(
n -> System.out.println("Hello, " + n),
() -> System.out.println("No name provided")
);
// or() — fallback to another Optional
Optional<String> result = Optional.<String>empty()
.or(() -> Optional.of("default value"));
// stream() — bridge Optional into Stream pipelines
List<String> names = List.of(opt1, opt2, opt3).stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());// Immutable collections in one line
List<String> list = List.of("a", "b", "c");
Set<String> set = Set.of("x", "y", "z");
Map<String, Integer> map = Map.of("a", 1, "b", 2);
// list.add("d"); // ❌ UnsupportedOperationException — truly immutable// Java 8: had to declare a new variable
BufferedReader reader1 = new BufferedReader(new FileReader("file.txt"));
try (BufferedReader r = reader1) {
// use r
}
// Java 9: use an effectively-final variable directly
BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
try (reader) {
// use reader directly — cleaner
}✅ Adopt modules for new, large applications — not worth retrofitting small existing apps
✅ Use takeWhile/dropWhile instead of manual loops for ordered-stream slicing
✅ Use Map.of()/List.of() for constant, small immutable collections — not for large or mutable data
❌ Don't fight the module system with --add-opens/--add-exports flags everywhere — that's a sign your module boundaries are wrong
- Libraries relying on internal JDK classes (
sun.misc.*, etc.) may break — strong encapsulation started here (fully enforced by default in Java 17) -
java.xml.bind(JAXB),java.xml.ws(JAX-WS) and other Java EE modules were deprecated for removal — add them as explicit dependencies if needed -
Stringinternal representation changed tobyte[](Latin-1/UTF-16 compact strings) — transparent, but reduces memory footprint significantly