Features Java 16 Brings to Developers

Features Java 16 Brings to Developers

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

Živković Miloš

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 behindsealedis 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 classpublic 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”-warnings when 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 (thepattern), and for various statements and expressions to test that “shape” against their input (thematching). — 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,s gets assigned a value. On the contrary,s has no value if pattern matching fails.

Thus this code can complete normally. You don’t havean unreachable code.s gets value assigned if conditional passes, if nots is 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 switch (Preview)

JDK 16: The new features in Java 16

Photo by Christina MorillofromPexels