From Java 8 to Java 15 in Ten Minutes
Tags: java, programming, functional
Published: 2020-12-07 15:13:51

This blog will give you samples of awesome new feature added since Java 7. I’ll showcase at least one major improvement for each Java version, all the way to Java 15 which was released in fall 2020. Java now fully supports **lambdas**, **functional programming**, type inference via `var`, **immutable collections** with simple constructors, and **multi-line strings**. Moreover, there are exciting new experimental features like **data classes** (`record`), and `sealed` classes. Finally I’ll talk about the **Java REPL** which offers high value for quick experiments.

**Table of Contents**:
* [**Functional programming**](#functional-programming) (Java 8)
* [**`Streams`**](#streams) (Java 8)
* [**`Optional`**](#optional) (Java 8)
* [**`JShell`**](#jshell) (Java 9)
* [**Factory Method for Immutable Collections**](#immutable) (Java 9)
* [**Type Inference with `var`**](#inference) (Java 10)
* [**Single Source File Launch**](#file-launch) (Java 11)
* [**Switch Expression**](#switch) (Java 12: experimental, full feature: Java 14)
* [**Multi-line Strings**](#multi-line-strings) (Java 13: experimental, full feature: Java 15)
* [**Data Classes: `record`**](#record) (Java 14: experimental)
* [**`instanceof` without Cast**](#instanceof) (Java 14: experimental)
* [**Sealed classes**](#sealed) (Java 15: experimental)
* [*Bonus: Updated Licensing Terms Starting with Java 8*](#licensing)

# <a name="functional-programming"></a> Functional Programming (Java 8)

In Java 8, functional programming and lambdas were added as language features. The two core paradigms of [functional programming](https://www.freecodecamp.org/news/an-introduction-to-the-basic-principles-of-functional-programming-a2c2a15c84/) are **immutable values** and elevating **functions** to first class citizens. Data goes through a pipeline of modification steps, where each step takes some input and maps it to a new output. Functional programming can be used with `Streams` and null-safe monads (`Optional`) in Java as shown below...

# <a name="streams"></a> Streams (Java 8)

For your average computer program, you often have to work with a list of values and perform a given **transformation on each value**. Prior to Java 8, you had to use a **`for` loop** for this transformation, but from now, you can use [`Streams`](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html) as follows:

```js
Stream.of("hello", "great")
    .map(s -> s + " world")
    .forEach(System.out::println);
> hello world
> great world
```

The `map` function takes as input a lambda, which will be applied to all elements in the stream.

`Streams` can work on `Lists`, `Sets`, and `Maps` (via transformation). Thanks to Streams, you can get rid of pretty much all loops in your code!👌

# <a name="optional"></a> Optional (Java 8)

Another common problem in Java were **Null Pointer Exceptions**. So, Java introduced [Optional](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html) – a monad that wraps a reference which might or might not be null. Applying updates to this Optional can be done in a functional way:

```js
Optional.of(new Random().nextInt(10))
    .filter(i -> i % 2 == 0)
    .map(i -> "number is even: " + i)
    .ifPresent(System.out::println);
> number is even: 6
```

In the snippet above, we create a random number, wrap it inside an Optional object, and then only print the number if it is even.

# <a name="jshell"></a> JShell (Java 9)

Finally, we have a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) for Java, and its name is [JShell](https://docs.oracle.com/javase/9/jshell/introduction-jshell.htm#JSHEL-GUID-630F27C8-1195-4989-9F6B-2C51D46F52C8)!😊 In a nutshell, JShell allows to experiment with Java snippets without writing and compiling a full Java class. Instead, you can **execute one command at a time**, and you immediately see the result. Here’s a simple example:

```js
$ <JDK>/bin/jshell
jshell> System.out.println("hello world")
hello world
```

Folks familiar with interpreted languages like JavaScript or Python have had the pleasure of a REPL for a long time, but so far, this feature was missing in Java. JShell allows to define **variables**, but also more complex entities like **multi-line functions**,  classes, and perform **loops**. Moreover, JShell supports auto-completion, which comes in handy if you don’t know the exact methods offered by a given Java class.

# <a name="immutable"></a> Factory Methods for Immutable Collections (Java 9)

Simple initialization of `Lists` has been missing in Java for a long time, but those times are over now. 😅 Previously you had to do something like this:

```js
jshell> List<Integer> list = Arrays.asList(1, 2, 3, 4)
list ==> [1, 2, 3, 4]
```

This is now simplified as follows:

```js
jshell> List<Integer> list = List.of(1, 2, 3, 4)
b ==> [1, 2, 3, 4]
```

This fancy `of(...)` method exists for [List](https://docs.oracle.com/javase/9/docs/api/java/util/List.html), [Set](https://docs.oracle.com/javase/9/docs/api/java/util/Set.html) and [Map](https://docs.oracle.com/javase/9/docs/api/java/util/Map.html). They all create an immutable object in just one simple line of code.

# <a name="inference"></a> Type Inference with `var` (Java 10)

Java 10 introduced the new [var](https://developer.oracle.com/java/jdk-10-local-variable-type-inference.html) keyword which allows to **omit the type** of a variable.

```js
jshell> var x = new HashSet<String>()
x ==> []

jshell> x.add("apple")
$1 ==> true
```

In the snippet above, the type of `x` can be **inferred** to be HashSet<String> by the compiler.

This feature helps to **reduce boilerplate code** and **improve readability**. There’s some limitations to it though: you can only use `var` inside of method bodies, and the compiler will infer the type at compile time, so everything is still statically typed.

# <a name="file-launch"></a> Single Source File Launch (Java 11)

Previously, when you had written a simple Java program consisting of one file, you had to first compile the file with `javac` and then run it with `java`. In Java 11, you can do both steps with one command:

`Main.java`:
```js
public class Main {
  public static void main(String[] args) {
    System.out.println("hello world");
  }
}
```
```js
$ java ./Main.java
hello world
```

For simple starter programs or experiments consisting of just one Java class, this feature for [launching single source files](https://www.baeldung.com/java-single-file-source-code) will make your life easier.

# <a name="switch"></a> Switch Expression (Java 12) 

Java 12 brought us [Switch expressions](https://docs.oracle.com/en/java/javase/13/language/switch-expressions.html). Here’s a quick showcase of how the expression differs from the old switch statement.

The **old switch statement** defines the flow of the program:

```js
jshell> var i = 3
jshell> String s;
jshell> switch(i) {
   ...>     case 1: s = "one"; break;
   ...>     case 2: s = "two"; break;
   ...>     case 3: s = "three"; break;
   ...>     default: s = "unknown number";
   ...> }
jshell> s
s ==> "three"
```

In contrast, the **new switch expression** returns a value:

```js
jshell> var i = 3;
jshell> var x = switch(i) {
   ...>     case 1 -> "one";
   ...>     case 2 -> "two";
   ...>     case 3 -> "three";
   ...>     default -> "unknown number";
   ...> };
x ==> "three"
```

To sum up, the old switch statement is for program flow, and the new switch expression resolves to a value.

Notice that this new switch statement is a sort of **mapping** function: there’s one input (in the above case `i`), and there’s one output (here `x`). This is actually a [pattern matching](https://en.wikipedia.org/wiki/Pattern_matching) feature which helps to make Java more compatible with the **functional programming** principles. A [similar switch statement](https://docs.scala-lang.org/tour/pattern-matching.html) has been available in Scala for a while.

A couple of things to note:
* Instead of double points, we use arrows `->`
* There’s no need for `break`
* The default case can be omitted when all possible cases are considered
* To enable this feature with Java 12, use `--enable-preview --source 12`

# <a name="multi-line-strings"></a> Multi-line Strings (Java 13)

Did you ever have to define a long **multi-line String** like JSON or XML? So far, you’d probably squash everything on one line and use newline characters `\n`, but this makes the String much harder to read. Here comes Java 13 with [multi-line Strings](https://blogs.oracle.com/javamagazine/text-blocks-come-to-java)!💪

Sample case:
```js
public class Main
{ 
  public static void main(String [] args)
  {
    var s = """
        {
            "recipe": "watermelon smoothie",
            "duration": "10 mins",
            "items": ["watermelon", "lemon", "parsley"]
        }""";
    System.out.println(s);
  }
}
```

Now, we run the main Method via single-file-launch:

```js
java --enable-preview --source 13 Main.java

{
    "recipe": "watermelon smoothie",
    "duration": "10 mins",
    "items": ["watermelon", "lemon", "parsley"]
}
```

The resulting String spans multiple lines, quotation marks `""` are left intact, and even tabs `\t` are preserved!

# <a name="record"></a> Data Classes: `record` (Java 14)

Of all the new features in this article, this is probably the one I’m most excited about: finally, there are **data classes** in Java! These classes are declared with the [record](https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/Record.html) keyword and have automatic Getters, a constructor, and equals() method etc. In short, you can get rid of a huge chunk of boilerplate code!🙌🎉

```js
jshell> record Employee (String name, int age, String department) {}
|  created record Employee

jshell> var x = new Employee("Anne", 25, "Legal");
x ==> Employee[name=Anne, age=25, department=Legal]

jshell> x.name()
$2 ==> "Anne"
```

Scala has a similar feature with [case classes](https://docs.scala-lang.org/tour/case-classes.html), and Kotlin with [data classes](https://kotlinlang.org/docs/reference/data-classes.html). In Java, lots of developers used [Lombok](https://projectlombok.org/) so far, which offered pretty much the features that now inspired `records` for Java 14. More details can be found in this [Baeldung article](https://www.baeldung.com/java-record-keyword).

# <a name="instanceof"></a> `instanceof` without Cast (Java 14)

Prior versions of Java already contained the `instanceof` keyword:

```js
Object obj = new String("hello");
if (obj instanceof String) {
  System.out.println("String length: " + ((String)obj).length());
}
```

The unfortunate part: First we check that `s` is of type `String`, then we cast it again to retrieve its length.

Now with Java 14, the compiler is smart enough to [infer the type automatically after the instanceof check](https://blogs.oracle.com/javamagazine/pattern-matching-for-instanceof-in-java-14):

```js
Object obj = new String("hello");
if (obj instanceof String mystr) {
  System.out.println("String length: " + mystr.length());
}
```

# <a name="sealed"></a> Sealed classes (Java 15)

With the [sealed keyword](https://docs.oracle.com/en/java/javase/15/language/sealed-classes-and-interfaces.html), you can **restrict** which classes can **extend** a given class or interface. Here’s an example:

```js
public sealed interface Fruit permits Apple, Pear {
    String getName();
}

public final class Apple implements Fruit {
    public String getName() { return "Apple"; }
}

public final class Pear implements Fruit {
    public String getName() { return "Pear"; }
}
```

So how does this help us? Well, now you know how many `Fruits` there are. This is actually an important step into the direction [fully supported pattern matching](https://blogs.oracle.com/javamagazine/inside-the-language-sealed-types), where you can sort of treat classes like enums. This `sealed` feature goes together nicely with the new `switch` expression explained previously.

# <a name="licensing"></a> Bonus: Updated Licensing Terms Starting with Java 8 

One last topic for this article: **licensing**. Most of you heard that [Oracle stopped updates for Java 8](https://www.oracle.com/java/technologies/java-se-support-roadmap.html) (for the free commercial version). So here are your options:
* Use a **newer Oracle JDK** version (Oracle offers free security updates for only 6 months after each release)
* Use and **old JDK** version at your own risk
* Use an old **OpenJDK** Java version, those still get security updates from the open source community or a third party vendor
* Pay Oracle for **premier support** (e.g. Java 8: support until 2030)

Below you can see the tentative Oracle support durations per JDK:

![Oracle Java SE Support Roadmap](https://dev-to-uploads.s3.amazonaws.com/i/009ln0icghz4w859acuf.PNG)

Oracle’s new licensing model is influenced by the new [release cycle](https://blogs.oracle.com/java-platform-group/update-and-faq-on-the-java-se-release-cadence): Oracle will bring out a new Java version every 6 months. This new release cycle helps Oracle to improve Java at a faster pace, get quicker feedback via experimental features, and catch up with more modern languages like [Scala](https://www.scala-lang.org/), [Kotlin](https://kotlinlang.org/) and [Python](https://www.python.org/).

If you’re interested in more licensing details, checkout this [Medium]( https://medium.com/@javachampions/java-is-still-free-2-0-0-6b9aa8d6d244) article.

# Wrap up

Java has gone a long way in the last 6 years, there's actually been 8 new Java releases since then!🚀 All these awesome new features help to make Java a competitive option compared to other JVM-based rivals (Scala and Kotlin).

If you're looking for even more in-depth details on new Java features since Java 8, I can recommend this [DEV article by Andrew](https://dev.to/awwsmm/20-reasons-to-move-on-from-java-8-1dio) as well as this [article by David Csakvari](https://advancedweb.hu/a-categorized-list-of-all-java-and-jvm-features-since-jdk-8-to-15/).

I had a blast writing this article🔥 Thanks for reading😊 What's your favorite feature in a recent java release? I'd love to get a feedback from you! Cheers!