Making Use of Sealed Classes in Java - Venkat Subramaniam

In the intro to this talk, Venkat Subramaniam goes over the motivation for introducing the concept of Sealed Classes into the language. Most implementors of libraries may have a specific intent for their library. If a library is extensible, it may unknowingly introduce code that cannot be handled.

Sealed Interfaces

The second part of the talk covered an example and information reprised from another talk, where he explained how a sealed interface works -

A sealed interface allows you to limit how many classes implement the interface

sealed interface TrafficLight {}

final class Redlight implements TrafficLight {}
final class GreenLight implements TrafficLight {}
final class YellowLight implements TrafficLight {}

In the above example -

  • All classes in the same file implementing the interface and legitimate
  • A class in another file that attempts to implement the interface will get an error
sealed interface TrafficLight permits RedLight, GreenLight, YellowLight, FlashingLight;

Defining multiple final classes in a single file can get unwieldy. Therefore it is possible to specify the names of the classes that are permitted, as shown in the above example - using the permits keyword.

Compiler Errors

The compiler will protect the developer from

  • failure to implement a class that extends from a sealed interface.
  • Failure to mark a class that extends a sealed interface as final. This would defeat the purpose of having a closed hierarchy.
  • Failure to extend a sealed class.
sealed interface TrafficLight{}
sealed interface TrafficLight{}

class Redlight implements TrafficLight {}
sealed class YellowLight implements TrafficLight {}

Benefits of Sealed Classes

Better Modelling - You can design with intent around your Domain model

Better compiler checks

Enhanced Pattern Matching - This isn’t available currently but will be in future releases of Java. The presenter gave a tangential example using a switch statement where the compiler complained when all possible values of an enum weren’t handled. Something similar would be possible in the future with sealed classes or interfaces.

enum State { A , B , C }

return switch(state) {
	case A -> "got A";
	case B -> "got B";
	// Compiler with error, complaining that not all states were handled