JavaのSealed Classesについて

この記事は GMOアドマーケティング Advent Calendar 2021 13日目の記事です。

GMOアドマーケティングのT.Nです。

Java 17でSealed ClassesがPreviewからStandardになりました。  

弊社でも先日一部のプロダクトをJava 17にバージョンアップしたので、
今後Sealed Classesを活用していけるように記事にまとめました。

今回の記事は全体的にJEP 409 を参考にしています。

Sealed Classesとは

簡単に説明すると、
extends、implementsできるクラスを制限するための仕組みです。
sealed、non-sealed、permitsという新しい文法を使って実現できます。

Sealed Classesを活用することで、
クラスの階層でドメイン知識を表現しやすくなります。

sealedをつけたクラス、インターフェースは、
permitsで指定したクラス、インターフェースでしかextends、implementsできないようになります。

non-sealedをつけたクラス、インターフェースは、
どのクラス、インターフェースからでもextends、implementsできるようになります。

ソースコードで説明すると以下のようになります。
(ReeMo、AkaNe、GMO SSPは弊社のプロダクトです。)

抽象クラスの場合

インターフェースの場合


以下のように内部クラスで定義した場合は、permitsを省略することができます。  
以下のようにrecordにも適用することができます。 recordと組み合わせた場合は、代数的データ型と呼ばれるものになります。
recordはfinalであるため、sealedやnon-sealedを指定することはできません。  

Sealed Classesのルール

Sealed Classesのルールをまとめました。
以下のルール通りに実装しないとコンパイルエラーになります。

  • permitsに指定されたクラスは、sealedクラスを必ずextends、implementsする必要がある。
  • sealedクラスとpermitsで指定されたクラスは、同じpackage、またはmoduleに存在する必要がある。
  • permitsで指定されたクラスは、sealedクラスを直接継承する必要がある。
  • permitsで指定されたクラスでは、sealed、non-sealed、finalのいずれかを指定する必要がある。

Reflection APIについて

Sealed Classesの追加に伴い、
Reflection APIに以下のメソッドが追加されました。
  • Class<?> getPermittedSubclasses()
  • boolean isSealed()
上の例で使用したクラスでの実行結果は以下のようになりました。
最初にsealedがつけられた一番上の階層のクラスだけ、
getPermittedSubclassesの結果を取得でき、isSealedもtrueになりました。  

まとめ

今回の記事でSealed Classesの仕様について確認することができました。

Sealed Classesを活用することで、
設計、実装の意図をソースコードで表現しやすくなると思うので、
今後Sealed Classesが普及していくと良いです。

明日はT.Mさんによる「マネージャーのキャリアパス」です。
引き続き、GMOアドマーケティング Advent Calendar 2021 をお楽しみください!

■エンジニア採用ページ ~福利厚生や各種制度のご案内はこちら~
https://note.gmo-ap.jp/n/n02cbeb6edb0d

■noteページ ~ブログや採用、イベント情報を公開中!~
https://note.gmo-ap.jp/