Understanding Sealed classes in Java 17

Advertisements

Sealed classes are an enhancement to the language included with LTS version 17 (included since version 16) of Java. Sealed classes or interfaces allow us to restrict what other classes and interfaces can extend from them.

Note: The sealed classes don’t have as goal to replace the final keyword

The goal of sealed classes or interfaces is to provide a way to allow a class to be widely accessible but not widely extensible. These can be extended or implemented only by those classes and interfaces that are explicitly allowed.

How to use it?

A class or interface is sealed by applying the sealed modifier to its definition, after any extends or implements the permits clause must be added followed by the classes that we allow to be extended.

public abstract sealed class Shape
    permits Circle, Rectangle, Square, WeirdShape { ... }

Then, in the implementations (permitted classes) we must extend the sealed class.

public final class Circle extends Shape { ... }
public final class Rectangule extends Shape { ... }
public final class Square extends Shape { ... }
public final class WeirdShape extends Shape { ... }

Permitted Sub-classes and its rules

Each of the “permitted” sub-class must use a modifier to describe how to propagate the sealing initiated by its superclass:

Advertisements
  • A “permitted” subclass might apply the final modifier to avoid spreading further.
  • A “permitted” subclass might apply the sealed modifier followed by the clause permits to extend to other sub-classes in its hierarchy.
  • A “permitted” sub-class might apply the non-sealed modifier, so it reverts on its own hierarchy the “sealed” by the super-class and opening to extension to other unknown classes by the super class.

Let’s see some examples:

public abstract sealed class Shape
    permits Circle, Rectangle, Square, WeirdShape { ... }

public final class Circle extends Shape { ... }

public sealed class Rectangle extends Shape 
    permits TransparentRectangle, FilledRectangle { ... }
public final class TransparentRectangle extends Rectangle { ... }
public final class FilledRectangle extends Rectangle { ... }

public final class Square extends Shape { ... }

public non-sealed class WeirdShape extends Shape { ... }

In summary, at least one of the final , sealed or non-sealed modifiers must be applied to the permitted sub-classes.

Sealed Interfaces

As it has been mentioned previously, interfaces can also be sealed in the same way as classes. You must follow the same rules as the sealed classes, apply the sealed modifier and follow the permits clause with the list of allowed implementations.

public sealed interface Expr
    permits ConstantExpr, PlusExpr, TimesExpr, NegExpr { ... }

public final class ConstantExpr implements Expr { ... }
public final class PlusExpr     implements Expr { ... }
public final class TimesExpr    implements Expr { ... }
public final class NegExpr      implements Expr { ... }

Sealing and record classes

The record classes introduced in Java 15 are implicitly final so it is consistent with the rules for the allowed subclasses mentioned above.

package com.example.expression;

public sealed interface Expr
    permits ConstantExpr, PlusExpr, TimesExpr, NegExpr { ... }

public record ConstantExpr(int i)       implements Expr { ... }
public record PlusExpr(Expr a, Expr b)  implements Expr { ... }
public record TimesExpr(Expr a, Expr b) implements Expr { ... }
public record NegExpr(Expr e)           implements Expr { ... }

Conclusions

Definitely the sealed classes and interfaces are a great inclusion to the Java language, allowing to cover some limitations in the language for the creators of APIs and libraries, where in some cases we want to restrict the extensibility of our classes without limiting their accessibility.

This new feature opens the doors to incorporate many other future features to the language, such as the switch pattern matching that is being worked on in JEP 406

References

Advertisements

Leave a Reply

Your email address will not be published.