# From JDK 8 to 11

2019-11-14 — Nailcan Küçük
Tags: java, jdk

A walkthrough of the most important features and improvements introduced between Java 8 and Java 11, including Project Jigsaw, ZGC, var keyword, JShell, and more.

Canonical: https://www.nailcankucuk.com/blog/jdk-8-to-11/

---

## From JDK 8 to 11

![Java 8 to 11](/images/blog/jdk-8-to-11-cover.png)

After its first beta in 1995 and the **1.0** release in January 1996, Java shipped a new major version roughly every two years — up to **Java 6** in 2006. Then came a five-year wait for **Java 7** in 2011.

Following the **Java 8** release in March 2014, Oracle changed its release policy: it introduced short-term support transition releases alongside long-term support (LTS) versions. Interim releases are supported until the next interim or LTS version ships.

**Java 9** arrived in September 2017, **Java 10** in March 2018, and the current LTS version, **Java 11**, landed in September 2018. At the time of writing, **Java 13** (released September 2019) was the latest available version.

Below I cover the most notable changes when migrating from Java 8 to Java 11.

---

## Modularization — Project Jigsaw

Introduced with Java 9, Project Jigsaw lets you decompose monolithic applications into discrete modules. Classes that serve the same purpose are grouped under a single *source root*, forming self-contained modules within the application.

Modularity can be seen as a middle ground between a monolith and a microservice architecture. Each module encapsulates all the layers it needs to fulfill a single responsibility. This makes it easier to later migrate a monolith to microservices.

Inter-module accessibility is declared in a `module-info.java` file located at the module root.

Suppose the project has two modules: **com.demo.sql** and **com.demo.audit**. The **sql** module has two packages: ***connection*** and ***crud***.

If we want to keep ***connection*** private to the **sql** module but expose ***crud*** to other modules, `module-info.java` looks like this:

```java
module sql {
  exports com.demo.sql.crud;
}
```

If the **audit** module needs to access classes inside ***sql.crud***, it declares the dependency in its own `module-info.java`:

```java
module audit {
  requires com.demo.sql.crud;
}
```

Java 9 ships with roughly 40 standard modules (`java.base`, `java.desktop`, `java.naming`, `java.sql`, …), visible under `$JAVA_HOME/jmods`.

For more details, see [Project Jigsaw on Baeldung](https://www.baeldung.com/project-jigsaw-java-modularity).

---

## JEP 330: Launching Single-File Source Programs

Before Java 11, running a class with a `main` method from the console required an explicit compile step followed by execution:

```java
class Test {
  public static void main(String... args) {
    System.out.println("Application running...");
  }
}
```

```java
$javac -d classes Test.java
$java -cp classes Test
```

With Java 11, you can run a single-file program directly — no separate compile step needed:

```java
$java Test.java
```

---

## JEP 328: Java Flight Recorder

A low-overhead profiling tool for monitoring JVM applications at runtime.

Some issues — like memory leaks that take days to surface — are difficult to reproduce locally. Flight Recorder captures these events in production and lets you analyze root causes after the fact. Enable it with the `-XX:StartFlightRecording` JVM flag.

---

## JEP 333: ZGC

A new, scalable, low-latency garbage collector. Key design targets:

- Heap sizes up to terabytes
- Maximum GC pause time of 10 ms
- Maximum throughput overhead of 15%

---

## JEP 286: Local-Variable Type Inference (Java 10)

You can now declare local variables using the `var` keyword instead of an explicit type:

**Where `var` can be used:**
- Local variables with an initializer
- Index variables in `for` loops

```java
var testWord = "Hello, Test";
var age = 22;
var isAvailable = true;
for (var i = 0; i < 10; i++)
for (var user : users)
```

**Where `var` should NOT be used:**
- Variables declared without an initializer
- Variables initialized to `null`
- Array declarations
- Method parameters
- Method return types

```java
var test;
var test = null;
var test = {0, 1, 2};
public void get(var id);
public var get(Long id);
```

---

## JEP 323: Local-Variable Syntax for Lambda Parameters

Lambda parameters can now use `var`, enabling annotations in implicit-style lambdas:

```java
(Item a, int b) -> a.create(b);       // Explicit types
(a, b) -> a.create(b);                // Implicit types
(var a, var b) -> a.create(b);        // Implicit with var
```

Before `var`, adding an annotation to a lambda parameter required switching to the explicit form. Now `var` allows annotations in the implicit style:

```java
(@Nonnull var a, var b) -> a.create(b);
```

Mixing explicit and implicit types in the same lambda parameter list is not allowed:

```java
(Item a, b) -> a.create(b);      // invalid
(var a, b) -> a.create(b);       // invalid
(var a, int b) -> a.create(b);   // invalid
```

---

## JShell

The REPL (Read-Eval-Print Loop) tool introduced in Java 9. JShell lets you write and execute Java code directly in the terminal — no need to create a file, compile it, and run it separately.

For more information, see the [Introduction to JShell](https://docs.oracle.com/javase/9/jshell/introduction-jshell.htm) in the Oracle documentation.

---

## Optional — New Methods

**`ifPresentOrElse()`:** Instead of writing an `if-else` block around `Optional.isPresent()`, you can pass both the present and absent handlers directly:

```java
if (optionalPrice.isPresent()) {
  updatePrice(optionalPrice.get());
} else {
  finishOperation();
}
```

becomes:

```java
optionalPrice.ifPresentOrElse(this::updatePrice, this::finishOperation);
```

**`or()`:** Provides an alternative `Optional` when the original is empty:

```java
Optional<Person> optionalPerson = findPersonById(1L).or(() -> Optional.of(new Person()));
```

---

## CompletableFuture — New Methods

**`orTimeout()`:** Completes the future exceptionally if it does not complete within the given timeout:

```java
CompletableFuture<String> cf = future.orTimeout(30, TimeUnit.SECONDS);
```

**`completeOnTimeout()`:** Completes the future with a default value if it does not complete within the given timeout:

```java
CompletableFuture<String> cf = future.completeOnTimeout("Default completed value", 30, TimeUnit.SECONDS);
```

---

These are some of the most impactful changes across the dozens of differences between Java 8 and Java 11. For the full picture, refer to the [JDK 11 Documentation](https://docs.oracle.com/en/java/javase/11/index.html).
