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
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
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
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
Pattern matching exists a long time. You can find it for example in Elixir.
In Java, there’s a lot ofinstanceof
conditions. 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,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 have an 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.
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)