Java 17 Sealed Classes
Java 17, the latest Long-Term Support (LTS) version, introduces several new features and enhancements aimed at improving code readability, maintainability, and security. One of the most notable additions to Java 17 is the introduction of sealed classes. In this blog post, we’ll explore what sealed classes are, how they work, and why they’ve been introduced into the Java ecosystem.
Understanding Sealed Classes
Sealed classes are a new feature in Java that provide more control over class hierarchies and help enforce stronger encapsulation. By declaring a class as sealed, developers can specify which classes are allowed to extend it. This effectively restricts the subclasses to a predefined set, thereby preventing unauthorized extensions. Sealed classes are declared using the sealed
modifier followed by the permitted subclasses within curly braces.
Syntax
The syntax for declaring a sealed class is as follows:
public sealed class MySealedClass permits Subclass1, Subclass2, Subclass3 {
// Class members and methods
}
Example: Implementing Sealed Classes
Let’s illustrate the concept of sealed classes with a simple example. Suppose we have a sealed class Shape
, which can be extended by Circle
, Square
, and Triangle
classes.
public sealed class Shape permits Circle, Square, Triangle {
// Class members and methods
}
final class Circle extends Shape {
// Circle-specific implementation
}
final class Square extends Shape {
// Square-specific implementation
}
final class Triangle extends Shape {
// Triangle-specific implementation
}
In this example, the Shape
class is declared as sealed, and it explicitly permits only Circle
, Square
, and Triangle
classes to extend it.
Note: Any attempt to create a subclass outside of this permitted set will result in a compilation error.
java: invalid permits clause
See the complete example.
package org.websparrow;
sealed abstract class Shape permits Circle, Square, Triangle {
// Common methods and fields for Shape
public abstract double area();
}
final class Circle extends Shape {
private final double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public String toString() {
return "Circle";
}
}
final class Square extends Shape {
private final double sideLength;
public Square(double sideLength) {
this.sideLength = sideLength;
}
@Override
public double area() {
return sideLength * sideLength;
}
@Override
public String toString() {
return "Square";
}
}
final class Triangle extends Shape {
private final double base;
private final double height;
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
@Override
public double area() {
return 0.5 * base * height;
}
@Override
public String toString() {
return "Triangle";
}
}
public class MySealedClass {
public static void main(String[] args) {
Shape circle = new Circle(5);
Shape square = new Square(4);
Shape triangle = new Triangle(3, 6);
System.out.println("Area of " + circle + ": " + circle.area());
System.out.println("Area of " + square + ": " + square.area());
System.out.println("Area of " + triangle + ": " + triangle.area());
}
}
Output:
Area of Circle: 78.53981633974483
Area of Square: 16.0
Area of Triangle: 9.0
Benefits of Sealed Classes
- Enhanced Readability: Sealed classes make class hierarchies more explicit by clearly defining which classes can extend them. This improves code readability and makes it easier for developers to understand the structure of the codebase.
- Stronger Encapsulation: By restricting subclassing to a predefined set, sealed classes enforce stronger encapsulation and prevent unintended inheritance. This helps prevent unexpected behavior and makes code more robust.
- Improved Maintainability: Sealed classes facilitate better code maintenance by reducing the risk of unintended subclassing. Changes to sealed classes are less likely to cause ripple effects throughout the codebase, as the set of permitted subclasses is explicitly defined.
- Compiler Safety: The use of sealed classes provides compile-time safety by detecting and preventing unauthorized subclassing at compile time. This helps catch errors early in the development process and reduces the likelihood of runtime exceptions.
Why Java Introduces Sealed Classes?
The introduction of sealed classes in Java 17 is driven by the need to address the limitations of the existing class inheritance model. Traditional class hierarchies in Java allow any class to be extended, leading to potential issues such as fragile base class problem, tight coupling, and difficulty in maintaining codebases. Sealed classes provide a mechanism for more controlled and predictable class hierarchies, helping developers write safer and more maintainable code.