DEV Community

Cover image for Features Java 16 Brings to Developers
Milos Zivkovic
Milos Zivkovic

Posted on • Originally published at levelup.gitconnected.com

Features Java 16 Brings to Developers

Živković Miloš

Learn about pattern matching, sealed classes, and more new Java features.

Java needs no introduction. It’s a programming language with many years under its belt. Recent updates brought several new features to the language: Sealed classes, pattern matching, and additional safety measures.

Sealed classes

JEP-397

The motivation behind sealed is to restrict concrete classes. Restricting concrete classes, will control implementation, and provide support for pattern matching.

// keyword here is sealed which enables permits

// permits lists classes that can extend sealed class public abstract sealed class Shape

permits Circle, Rectangle, Square { ... }

With basic interfacing, you don’t get reflectiveness. You don’t know about a finite set of concrete implementations.

With sealed classes, you get this reflective behavior. You know about the kind of types, you can have in your domain.

Enums tell about a finite set of values. Sealed classes tell about a finite amount of kind of values.

sealed interface Celestial

permits Planet, Star, Comet { ... }

final class Planet implements Celestial { ... }

final class Star implements Celestial { ... }

final class Comet implements Celestial { ... }

This hierarchy does not, however, reflect the important domain knowledge that there are only three kinds of celestial objects in our model. In these situations, restricting the set of subclasses or subinterfaces can streamline the modeling. — JEP-397

Warnings for value-based classes

JEP-390

Primitive wrapper classes are value-based classes. Examples of value-based classes are:Byte,Short,Integer,Long,Float,Double,Boolean, andCharacter). More on value-based classes can be found here.

As they are immutable objects, it is pointless to use constructors.

To prevent misuse, new annotation is around. This will put warnings each time, the compiler finds a value-based class constructor.

@jdk.internal.ValueBased

Encapsulation of JDK internals removed by default

JEP-396

This is to encourage users to use standard Java API. Still, you could choose relaxed encapsulation. If needed, but try to avoid it.

You’ll need to add props to the launcher of JVM. Below you can see the possible args, you can pass in. More on the arguments can be found here.

--illegal-access= permit | deny | debug | warn

Although this is embraced in JDK 16, you can face problems with earlier versions. This change was proposed after the JDK 9 was released.

Even today, with e.g. Java >=9, certain build tools print out “reflective access”-warningswhen building Java projects, which simply “feels not ready”, even though the builds are fine. — source

Pattern matching

JEP-394

Pattern matching exists a long time. You can find it for example in Elixir.

In Java, there’s a lot ofinstanceofconditions. Motivation to reduce operations leads to pattern matching.

Pattern matching allows the desired “shape” of an object to be expressed concisely (the_pattern_), and for various statements and expressions to test that “shape” against their input (the_matching_). — JEP-394

// a lot of boiler plate codeif (obj instanceof String) {

String s = (String) obj; // grr...

...

}

With pattern matching, we could get this code. Reduces boilerplate, does the casting, and declares the variable.

if (obj instanceof String s) {

// Let pattern matching do the work!

...

}

Pattern variable is in the scope where it matches. Thus code like this is valid.

if (a instanceof Point p) {

// p is in scope

...

}

// p not in scope here

if (b instanceof Point p) { // Sure!

...

}

You never have to worry about names now. Reusing existing names is possible if scopes are different.

What does pattern matching improve?

Reduces explicit casts. Which gives more readable code, in equality methods.

return (o instanceof CaseInsensitiveString) &&

((CaseInsensitiveString) o).s.equalsIgnoreCase(s);// to thisreturn (o instanceof CaseInsensitiveString cis) &&

cis.s.equalsIgnoreCase(s);

Look at the next example. If this conditiono instanceof String s, evaluates to true,sgets assigned a value. On the contrary,shas no value if pattern matching fails.

Thus this code can complete normally. You don’t have an unreachable code.sgets value assigned if conditional passes, if notsis safely discarded.

public void onlyForStrings(Object o) throws MyException {

if (!(o instanceof String s))

throw new MyException();// s has value at this point

System.out.println(s);

...

}

Conclusion

Java is evolving. Causes a lot of breaking changes. Causes a lot of problems.

Constant Java updates

Even so, we do need to adjust. Use new features so we create better software.

These are few features, I would take away. You can read more, in the section below.

Resources

JEP draft: Pattern Matching for the switch (Preview)

JDK 16: The new features in Java 16

Photo by Christina MorillofromPexels

Top comments (0)