Sealed Classes #
Description #
Enhance the Java programming language with sealed classes and interfaces. Sealed classes and interfaces restrict which other classes or interfaces may extend or implement them.
Sealed classes/interfaces where introduced through JEP-409 in Java 17. This functionality was avaiable as preview feature in Java 15 and 16 through JEP-360 and JEP-397.
Goals #
Main goals of this language improvement:
- Allow the author of a class or interface to control which code is responsible for implementing it.
- Provide a more declarative way than access modifiers to restrict the use of a superclass.
- Support future directions in pattern matching by providing a foundation for the exhaustive analysis of patterns.
Syntax #
This language feature relies on 3 new keywords:
sealed- Used to declare that a class/interface has a fixed set of allowed sub-classes/interfaces.non-sealed- A sub-class/interface of a sealed super-class/interface can use the non-sealed keyword to allow un-restricted sub-classes/implementations.permits- When working with a sealed class/interface permits keyword is used to declare thed fixed set of sub-classes/interfaces that exist.
Sub-classes/interfaces of a sealed type are required to declare if and how future subtypes can be defined.
This is achieved though the use of final (only for classes), sealed and non-sealed keywords.
Package structure
When working with a
sealedclass there are two options when it comes to package structure:
- Make sure all sub-types are in the same package
- Use the module system introduced in Java 9 which will allow the use of sub-types that are not in the same package
Usage #
In order to highlight the benefits of sealed types we’ll use as example a game engine with the following requirements :
- two types of
Characters:HeroandMonster - allow the engine user to define
Herocharacters - restrict the definition of
Monstercharacters
Considering the above requirements the class structure can look like this :
package com.javafeatures.sealedgame;
sealed interface Character permits Hero, Monster {}
non-sealed abstract class Hero implements Character { }
sealed class Monster implements Character permits Cyclop, Dragon { }
final class Dragon extends Monster { }
final class Cyclop extends Monster { }Switch pattern matching (Preview) #
While currently still in preview, the combination of switch expressions and sealed classes allows us to create exhaustive checks on the class type.
package com.javafeatures.sealedgame;
private static Color getAvatarBackgroundColor(Character character) {
return switch (character) {
case Hero hero -> Color.GREEN;
case Monster monster -> Color.RED;
};
}The compiler will make sure all possibilities are accounted for by either specifying all
types in the switch or by providing a default branch. In the above example if a new Character type would be added the developer
would be forced by the compiler to handle it in the switch expresion.