Optional.orElseThrow を一言でいうと
Optional.orElseThrow は
「中身があればその値を返し、なければ“ここで失敗だ”と明示的に例外を投げる」
ためのメソッドです。
「ここで値がないのは“普通のこと”ではなく、“バグやエラーとして扱いたい”」という場所で使います。null だったら NPE が“勝手に”飛ぶのではなく、「ここで、この例外を投げる」と自分で決めるための道具です。
まずは null ベースのコードと比べてみる
null でよくあるパターン
ユーザーを ID で検索して、見つからなければ「エラーにしたい」というケースを考えます。
User user = findByIdOrNull(id); // 見つからなければ null
if (user == null) {
throw new IllegalArgumentException("user not found: " + id);
}
// ここから先は user が必ずいる前提で処理を書く
process(user);
Javaここでは、
- メソッドが
nullを返すかもしれない - 呼び出し側で
if (user == null)を書く - 自分で例外を投げる
という流れになっています。
この if を書き忘れた瞬間に、どこか後ろで NullPointerException が飛びます。
Optional.orElseThrow で書くとどうなるか
同じことを Optional で書き直します。
User user =
findById(id) // Optional<User>
.orElseThrow(() -> new IllegalArgumentException("user not found: " + id));
process(user);
JavafindById が Optional<User> を返すようにしておけば、
中身があればその User が返ってきて、
中身がなければ、ラムダで渡した例外がその場で投げられます。
「ここで見つからないのは“普通”ではなく“エラー”」という意図が、orElseThrow という名前と例外クラスで、はっきりコードに刻まれます。
Optional.orElseThrow の基本的な形
引数なし版(Java 10 以降)
Java 10 以降には、引数なしの orElseThrow() もあります。
Optional<String> maybeName = Optional.empty();
String name = maybeName.orElseThrow(); // NoSuchElementException が投げられる
Javaこれは「中身がなければ NoSuchElementException を投げる」という固定の挙動です。Optional.get() と似ていますが、get() よりも「“なかったら例外”を明示している」感じが強いので、使うなら get() より orElseThrow() の方がまだマシです。
ただ、実務では「どんな例外を投げるか」を自分で決めたいことが多いので、引数あり版を使うことが多くなります。
例外を指定する版(よく使う形)
一番よく使うのは、こちらです。
T value = optional.orElseThrow(() -> new SomeException("message"));
Javaラムダで「投げたい例外」を作る関数を渡します。
中身があればそのまま値が返り、中身がなければそのラムダが呼ばれて例外が投げられます。
このときに渡す例外は、たいてい RuntimeException(非チェック例外)にします。
チェック例外を投げると、呼び出し側のシグネチャに throws を付ける必要が出てきて、扱いが重くなるからです。
orElse / orElseGet との違いを整理する
orElse は「なかったときの“値”を返す」
orElse は、「中身がなかったときに代わりの値を返す」メソッドです。
String name =
maybeName.orElse("ゲスト");
Javaここでは、「値がないのは普通にあり得る状況で、そのときは“ゲスト”という名前を使う」という設計になります。
orElseThrow は「なかったときは“失敗”にする」
一方で orElseThrow は、「値がないのは普通ではない。ここで処理を止めたい」というときに使います。
String name =
maybeName.orElseThrow(() -> new IllegalStateException("name must exist"));
Javaここでは、「ここまで来て名前がないのはシステムの状態としておかしい」というメッセージを、例外クラスとメッセージで表現しています。
設計としての線引きが大事
orElse を使うか orElseThrow を使うかは、設計の意思表示です。
「ここで値がないのは、普通に起こり得るケースか?」
「それとも、起きてほしくない異常なケースか?」
これを自分に問いかけて、
普通に起こり得る → orElse / orElseGet でデフォルトを決める
異常として扱いたい → orElseThrow で例外にする
という線引きをすると、コード全体の意図がかなりクリアになります。
現場でよくあるパターンを具体的に見る
リポジトリ層:Optional で返す
リポジトリ(DB アクセス)層では、よくこういうメソッドを定義します。
Optional<User> findById(long id);
JavaDB にレコードがなければ Optional.empty() を返す。
ここでは「見つからないこと自体」は異常ではなく、「データがない」という事実です。
サービス層:ビジネスルールとして orElseThrow する
サービス層では、「このユースケースでは、ユーザーが存在しないのはエラーだ」と決めることがあります。
User loadUserOrFail(long id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
}
Javaここで UserNotFoundException は、ドメインに即した独自例外です。
このメソッドを使う側は、もう Optional を意識しなくてよくなります。
User user = loadUserOrFail(id);
process(user); // user は必ず存在する前提で書ける
Java「どのレイヤーで Optional を終わらせて、どのレイヤーからは“必ずある前提”で扱うか」を決めるのが、設計上とても大事です。orElseThrow は、その“境界”を作るためのスイッチのような役割を持ちます。
Optional.get との違いと、なぜ orElseThrow を選ぶのか
get は「なかったら例外」だが、意図が見えにくい
Optional.get() も、「中身がなければ例外を投げる」メソッドです。
User user = maybeUser.get(); // 中身がなければ NoSuchElementException
Javaただし、get() は「なかったときに何の例外を投げるか」を選べません。
常に NoSuchElementException で、メッセージも貧弱です。
また、コードを読む側からすると、
「ここで empty の可能性をちゃんと考えているのか?」
「たまたま今は empty にならない前提なのか?」
が分かりにくい、という問題があります。
orElseThrow は「ここで失敗させる」という意思表示になる
orElseThrow を使うと、
User user =
maybeUser.orElseThrow(() -> new IllegalStateException("user must be loaded here"));
Javaのように、「ここで empty だったらこの例外で落とす」という意図がはっきりします。
例外クラスやメッセージに、
「なぜここで値が必須なのか」
「どういう状況を異常とみなしているのか」
を込められるので、将来バグ調査をするときにも役立ちます。
その意味で、get() より orElseThrow の方が、設計として“親切”です。
Optional.orElseThrow を使うときの注意ポイント
なんでもかんでも orElseThrow にしない
Optional を見た瞬間に、反射的に orElseThrow を書いてしまうのは危険です。
「ここで値がないのは、本当に異常か?」
「ユーザーに“見つかりませんでした”と返すのが正しいケースでは?」
といったことを、毎回ちゃんと考える必要があります。
例えば、検索画面で「該当データがありません」と表示したいだけなら、例外ではなく「0 件」という結果として扱うべきです。
その場合は、Optional ではなく List を返す設計にした方が自然です。
orElseThrow で止める場所を“外側”に寄せる
もう一つ大事なのは、「どのレイヤーで例外にするか」を決めることです。
リポジトリ層の深いところで orElseThrow してしまうと、
「このユースケースでは“見つからない”を普通に扱いたいのに、例外で止まってしまう」
ということが起きます。
なので、
下のレイヤー(リポジトリなど)は Optional を返す
上のレイヤー(サービスやコントローラ)で、「このケースでは例外にする」と決めて orElseThrow する
という構造にしておくと、再利用性と柔軟性が高くなります。
まとめ:Optional.orElseThrow を自分の言葉で説明するなら
あなたの言葉で Optional.orElseThrow を説明するなら、こうです。
「Optional.orElseThrow は、“ここで値がなかったら処理を続ける意味がない”という場所で使う、最後のゲート。
中身があればその値を返し、なければ自分で選んだ例外を投げることで、“ここから先は値が必ずある前提”にコードを切り替えられる。orElse が“なかったときの代替案”を決めるのに対して、orElseThrow は“なかったときは失敗にする”という設計の意思表示になる。」
