本文へスキップ
BecomeCoder

Javaデザインパターンコース · 第5章 モダンJavaとパターン ― 言語機能で置き換えられるもの · レッスン17

Optional ― 「値がないかもしれない」を型で表現する

ローカル実施

導入

Factory Methodのレッスンで、存在しない形状を渡すと例外を投げるようにしました。でも「見つからなかった」ことを、必ずしも例外で表現する必要はありません。特に「検索して見つからないこともある」ような処理では、null を返す設計がよく使われてきましたが、null は「呼び出し側がチェックし忘れる」という事故のもとです。Optional は、「値があるかもしれないし、ないかもしれない」という状態そのものを型で表現します。

説明

import java.util.Optional;
import java.util.List;

class ShapeRepository {
    private List<Shape> shapes;

    Optional<Shape> findByName(String name) {
        for (Shape s : shapes) {
            if (s.name.equals(name)) {
                return Optional.of(s);      // 見つかった
            }
        }
        return Optional.empty();            // 見つからなかった
    }
}

// 呼び出し側
Optional<Shape> found = repository.findByName("circle");
if (found.isPresent()) {
    System.out.println(found.get().name);
} else {
    System.out.println("見つかりませんでした");
}

// より簡潔に
String name = repository.findByName("circle")
    .map(s -> s.name)
    .orElse("不明な形状");
classDiagram
  class Optional~Shape~ {
    +of(shape) Optional
    +empty() Optional
    +isPresent() boolean
    +get() Shape
    +orElse(fallback) Shape
  }
  • Optional<Shape> を戻り値の型にすることで、「この呼び出しは見つからないこともある」ことがメソッドのシグネチャ(型)だけで分かります。null を返す設計だと、そのことはコメントを読まないと分かりません。
  • Optional.of(s) … 値がある場合の OptionalOptional.empty() … 値がない場合の Optional
  • .orElse("不明な形状") … 値がなかったときの代わりの値をその場で指定できます。if/else で毎回チェックするより簡潔です。
  • Factory Methodパターンで「見つからない場合は例外を投げる」実装をしましたが、「見つからないこと自体が正常な結果でありうる」場面(検索・検証など)では、例外より Optional の方が向いていることがあります。「異常だから例外」「あり得る結果の1つだから Optional」と使い分けるのが基本の指針です。

まとめ

この章で見たように、モダンJavaの言語機能はデザインパターンを「不要にする」わけではなく、パターンが解決しようとしていた問題そのものへの理解があってこそ、言語機能の価値も実感できます。sealed はFactory Methodが抱える「実装の網羅性」の課題に、ラムダはStrategyの「1行のためのクラス」という重さに、それぞれ言語仕様の側から応えたものです。次に新しいJavaのバージョンで機能が追加されたときも、「これはどのパターンの、どんな課題を解決しているのか」という視点で見てみてください。