【備忘録】Java 15で導入された`sealed`について覚書
はじめに
Java 15から導入されたsealed
について何がよいか理解しておらず、業務でJava 11からJava 17にアップグレードしてから有効活用できずにいた。
いくつか記事を読んだので、自分なりの理解を備忘録としてまとめておく。
sealedを簡単にまとめると
- sealedは直和型の実現をサポートする。直和型は、ある型が複数の具体的な型のいずれかとして存在することを表現する手法(TypeScriptで
type Foo = Hoge | Fuga
のような感じ)。 - sealedキーワードを使用することで、特定のクラスを継承するクラスを制限できる。
- 直和型は、結果やエラーを明示的に表現し、柔軟な処理フローを実現できる。
- Java 17の新機能でドメインモデリングの表現力を高めてみるでは除算の結果を直和型で表現し、成功した時と0で割った時などのエラーを表現していた。
- Java 16から導入された
instance of
やJava 20で導入された型ごとのswitch文を使って、異なる結果やエラーの型ごとに処理を記述できる。 - 直和型は、現実世界の概念を正確に表現するなど、ドメインモデリングの表現力を向上できる可能性がある。
sealedを使って結果とエラーを直和型で表現するのと、try-catch文を使うのはどちらが良いのか?
sealed
とinstanceof
を組み合わせると、Haskellで出てくるようなMaybe型のような書き方がこれまでに比べて安全にJavaで表現できるようになったが、どっちを使うべきかの見解を書いておく。
特徴
sealedを使って結果とエラーを直和型で表現する場合の特徴:
- 直和型を使用することで、結果とエラーを明示的に表現することができる。
- エラーが発生した場合でも、プログラムのフローが途中で中断しないで書ける。さらに、
instance of
やswitch
文を使って、異なる結果やエラーの型ごとに処理を記述することができる。
try-catch文を使用する場合の特徴:
- 慣れ親しんでいるため(?)、シンプルなケースでは使いやすい(はず)。
結局どっち?
どちらを使うべきかは、具体的なコンテキストや要件に依存しそう。
直和型を使う場合
- 複数の結果やエラーの型があり、それぞれに異なる処理が必要な場合。
- エラーの種類ごとに異なる処理を行いたい場合。
- エラーハンドリングを独自のフローで制御したい場合。
try-catch文を使う場合:
- 特定のエラーに対してのみ処理を行う場合。
- 既存のコードベースや慣習がtry-catch文を使用している場合。
おわりに
sealed
の使い所について、少し理解できたと思う。直和型でモデリングした時にDBなどからデータを取ってくるときはどうするべきなのか疑問が残った(リポジトリ層でデータをまるっと取得して、データの内容によってどの型かどうか判断してインスタンスを生成する感じか?)。その点については引き続き考えていきたい。