JavaでOptionalを使い始めると、orElse()とorElseGet()がよく似ていて迷いやすいです。結論からいうと、固定の代替値を返すなら orElse()、必要なときだけ処理を動かしたいなら orElseGet() と覚えると分かりやすいです。
このページでは、Java Optional の基本記事を読んだ次の一歩として、2つの違い、評価タイミング、使い分けのコツを初心者向けに整理します。

いちばん大事なのは、orElse() は Optional に値が入っていても引数側の式が評価される、という点です。
結論: orElse() と orElseGet() の違い
まずは結論だけを表で押さえましょう。
| 項目 | orElse() |
orElseGet() |
|---|---|---|
| 渡すもの | 代わりの値そのもの | 代わりの値を作る処理 |
| Optional に値があるとき | 引数側も評価される | 処理は実行されない |
| 向いている場面 | 固定文字列や定数を返すとき | 重い処理や副作用を避けたいとき |
まずは基本的な書き方を見てみよう
orElse() と orElseGet() は、どちらも Optional が空だったときの代替値を用意するメソッドです。
String name1 = Optional.ofNullable(getNickname())
.orElse("ゲスト");
String name2 = Optional.ofNullable(getNickname())
.orElseGet(() -> createGuestName());
orElse("ゲスト"): 「ゲスト」という値をそのまま返すorElseGet(() -> createGuestName()): 必要なときだけメソッドを動かして値を作る
orElseGet() で使っている () -> ... はラムダ式です。ここがピンとこない場合は、Java のラムダ式や関数型インターフェースの記事も一緒に見ると理解しやすくなります。
いちばん大事なのは「評価タイミング」の違い
見た目は似ていますが、実際には処理されるタイミングが違います。ここが orElse() と orElseGet() の本質です。
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> name = Optional.of("Alice");
String result1 = name.orElse(createDefaultName());
String result2 = name.orElseGet(() -> createDefaultName());
System.out.println(result1);
System.out.println(result2);
}
static String createDefaultName() {
System.out.println("default name created");
return "Guest";
}
}
このコードでは、Optional にすでに "Alice" が入っています。それでも orElse(createDefaultName()) のほうは、createDefaultName() が先に評価されます。
一方で orElseGet(() -> createDefaultName()) は、Optional が空のときだけ処理されます。つまり、値があるケースでは余計な処理を動かさない のが orElseGet() です。
イメージ orElse() は先に代替値を準備し、orElseGet() は必要になってから準備します
なぜこの違いが重要なのか
代替値が単なる固定文字列なら、両者の差はほとんど気になりません。ですが、代替値を作る処理が重い場合は話が変わります。
- データベースや API を呼び出す
- ログ出力やファイル処理をする
- UUID や日時を生成する
- 複雑な初期化メソッドを動かす
こうした処理を orElse() にそのまま書くと、Optional に値が入っていても毎回実行される 可能性があります。処理コストの無駄にもなりますし、ログや副作用が思わぬ形で発生することもあります。
どう使い分ければよいのか
orElse() が向いている場面
- 固定文字列を返したいとき
- すでに用意済みの定数を返したいとき
- 軽い値をそのまま置けば十分なとき
String role = Optional.ofNullable(getRole())
.orElse("USER");
このように、すでに値が決まっている場面なら orElse() で十分です。
orElseGet() が向いている場面
- 空のときだけメソッドを実行したいとき
- 代替値の生成コストが高いとき
- 副作用をできるだけ避けたいとき
String reportName = Optional.ofNullable(getReportName())
.orElseGet(() -> createReportName());
この例なら、既にレポート名がある場合に createReportName() を無駄に呼ばずに済みます。
よくある疑問
固定値なら常に orElse() でいいの?
はい、基本的にはそれで問題ありません。たとえば "guest" や 0 のような軽い値なら、orElse() のほうが読みやすいことも多いです。
じゃあ常に orElseGet() を使えば安全?
必ずしもそうではありません。orElseGet() は便利ですが、ラムダ式が入るぶん少しだけ読み手の負担が増えます。固定値なら素直に orElse()、処理を遅らせたいなら orElseGet() と使い分けるのが実用的です。
Supplier って何?
orElseGet() は内部的に「必要になったら値を返す処理」を受け取ります。これが Supplier という考え方です。まだ曖昧なら、関数型インターフェースの記事や、ラムダ式の記事を先に押さえると理解しやすいです。
Optional を学ぶ流れの中ではどう位置づければよい?
orElse() と orElseGet() の違いは、Optional の基本を理解したあとに押さえたい「次の一歩」です。Optional 自体がまだ曖昧な場合は、先に 値あり / empty / ofNullable() の流れを理解しておくと、この比較もかなり楽になります。
また、Optional<T> の <T> が分かりにくい人は、ジェネリクスの記事もあわせて読むと全体像がつかみやすくなります。
orElse() と orElseGet() の違いを理解すると、Optional を「なんとなく使う」状態から一歩進めます。null を安全に扱う考え方そのものを整理したい人は、Optional の基本記事や、NullPointerException の記事もあわせて読むのがおすすめです。
