Sealed Types in Java

September 30, 2019

Introduction

Java was kind of missing the possibility of defining sealed interfaces even though other languages may have implemented this feature already.

Sealed interfaces are just like usual interfaces, with the difference that it describes explicitly which classes have the right to implement them.

Let’s see how it could be working in practice in a near future with Java’s JEP.

Sealed Types : Restrict the Implementations

Sealed Types will give the possibility to restrict the implementations to specific classes.

But how does it work in practice ?

Let’s take a look at a supposition of implementation

public sealed interface Sex permits Male, Female {
}

Disclaimer : We’re talking about Sex here, not Gender. So Male and Female make sense even though more genders are generally accepted.

Now that our interface is sealed, let’s take a look at legal implementations (actually the two unique implementations)

public class Male implements Sex {}
public class Female implements Sex {}

And now let’s see what use cases are not possible anymore :

Anonymous Classes :

Sex sexAnon = new Sex(){}; // This becomes illegal

Lambdas (let’s suppose our interface falls into the definition of a functional interface) :

Sex sexLambda = () -> System.out.println(""); // Not permitted

Implementations by Classes (of course) :

public class ThirdType implements Sex {}

Switch Expressions And Pattern Matching

Reading the *Dependencies *section of JEP-360, we get the confirmation by the architects of Java that one of the purpose of bringing Sealed Types to Java is to bring Pattern Matching in the big picture.

Sealed types go well with records (JEP 359), which in turn lend themselves naturally to pattern matching. Switches over targets whose types are sealed can additionally be checked for exhaustiveness using sealing information when the patterns in the switch are type patterns or total deconstruction patterns.

Using the exhaustiveness feature of the new switch statement, we can now have a more concise way of making full use of these sealed types. This is because we know the exhaustive list of our interface.

Sex sexImpl = ...;
int sexCode = switch(sexImpl) {
    case Male m: yield 1;
    case Female f: yield 2;
}

This is a guess on how the switch statement could look like using pattern matching with the switch statement.

Totally Secure

In addition to the sealed type being enforced at compile-time, there is also a security at runtime. The sealed type and its implementations are reified in the class file.

Sealing, like finality, is enforced by both the language compiler and by the JVM. The sealed-ness of a type, and its list of permitted subtypes, are reified in the class file and enforced at runtime.

Conclusion

Allied to records and switch statements, sealed types will help deliver pattern matching to the Java language.