170. Combining sealed classes and records
As you know from Chapter 4, Java records are final classes that cannot be extended and cannot extend other classes. This means that records and sealed classes/interfaces can team up to obtain a closed hierarchy.For instance, in the following figure, we can identify the classes that can be good candidates to become Java records in the Fuel model:

Figure 8.6 – Indentify classes that can become Java records
As you can see, we have 4 classes that can become Java records: Coke, Charcoal, Hydrogen, and Propane. Technically speaking these classes can be Java records since they are final classes and don’t extend other classes:
public record Coke() implements SolidFuel {}
public record Charcoal() implements SolidFuel {}
public record Hydrogen() implements NaturalGas {}
public record Propane() implements GaseousFuel {}
Of course, the technical aspect is important but is not enough. In other words, don’t have to transform all classes in Java records just because it works and the code compiles. You also have to take into account the logic and the context of the application. Sometimes, a final class is all you need, otherwise, you may need an esoteric model made of a sealed interface with a few records and classes in the same source file (A.java):
public sealed interface A {
record A1() implements A {}
record A2() implements A {}
final class B1 implements A {}
non-sealed class B2 implements A {}
}
record A3() implements A {}
record A4() implements A {}
If you want to add the permits clause to A then you can do it as follows:
public sealed interface A
permits A.A1, A.A2, A.B1, A.B2, A3, A4 {…}
Done! Next, let’s see how Sealed Classes can help the compiler to better handle instanceof checks.
171. Hooking sealed classes and instanceof
Sealed Classes influence how the compiler understands the instanceof operator and implicitly how it performs internal cast and conversion operations.Let’s consider the following snippet of code:
public interface Quadrilateral {}
public class Triangle {}
So, we have here an interface (Quadrilateral), and a class that doesn’t implement this interface. In this context, does the following code compiles?
public static void drawTriangle(Triangle t) {
if (t instanceof Quadrilateral) {
System.out.println(“This is not a triangle”);
} else {
System.out.println(“Drawing a triangle”);
}
}
We wrote if (t instanceof Quadrilateral) {…} but we know that Triangle doesn’t implement Quadrilateral, so at first sight, we may think that the compiler will complain about this. But, actually, the code compiles because, at runtime, we may have a class Rectangle that extends Triangle and implements Quadrilateral:
public class Rectangle extends Triangle
implements Quadrilateral {}
So, our instanceof makes sense and is perfectly legal. Next, let’s close the Triangle class via the final keyword:
public final class Triangle {}
Since Triangle is final, Rectangle cannot extend it but it still can implement Quadrilateral:
public class Rectangle implements Quadrilateral {}
This time, the if (t instanceof Quadrilateral) {…} code will not compile. The compiler knows that a final class cannot be extended, so a Triangle will never be a Quadrilateral.So far, so good! Now, let’s restore the Triangle class as a non-final class:
public class Triangle {}
And, let’s seal the Quadrilateral interface to permits only Rectangle:
public sealed interface Quadrilateral permits Rectangle {}
And, the Rectangle class is final as follows (this time, it doesn’t extend Triangle):
public final class Rectangle implements Quadrilateral {}
Again, the compiler will complain about this check, if (t instanceof Quadrilateral) {…}. It is obvious that Triangle cannot be an instance of Quadrilateral since Quadrilateral is sealed and permits only Rectangle, not Triangle. However, if we modify the Rectangle to extend Triangle then the code compiles:
public final class Rectangle extends Triangle
implements Quadrilateral {}
So, in conclusion, Sealed Classes can help the compiler to better understand instanceof checks and to signal us when it doesn’t make sense.