「Optional に値が入っているのに、orElse に渡したメソッドが動いている」。ログに出るはずのない行が出て、首をかしげた方もいるはずです。

結論:orElse は値の有無にかかわらず引数を先に評価し、orElseGet は空のときだけ Supplier を呼びます。返ってくる結果は同じでも、引数に書いた処理が実行されるかどうかが違います。

筆者は Java Gold(SE 11 世代)と ORACLE MASTER Gold を保有しています。この記事では、実際にコードを動かした出力で違いを確かめます。理由は Oracle の API ドキュメントと言語仕様で裏付けます。

この記事で分かること:

  • orElse と orElseGet の違い(早見表と実行結果)
  • 値があっても orElse の引数が実行される理由
  • 使い分けの基準と、Java Gold(1Z0-826)での問われ方

※試験番号・配信終了日などの試験情報は、2026年10月12日に Oracle 日本の公式ページで確かめた内容です。Oracle が改定することがあるため、受験前に必ず最新の情報を確認してください。



結論:orElse と orElseGet の早見表

違いは「引数の型」と「引数が評価されるタイミング」の2点です。Optional に値があるときに返る結果は、どちらも中身の値で変わりません。

項目 orElse orElseGet
シグネチャ T orElse(T other) T orElseGet(Supplier<? extends T> supplier)
受け取るもの 値そのもの 値の作り方(Supplier)
引数の処理が動くとき 値があってもなくても毎回 空のときだけ
null を渡すと 許される(空なら null が返る) 空のときだけ NullPointerException
向く場面 定数・作成済みの変数 重い処理・副作用のある処理

横にスクロールできます

覚え方は「orElse は値を渡す、orElseGet は作り方を渡す」です。値を渡すには、渡す前にその値を作り終えている必要があります。

後輩
結果が同じなら、どっちを使っても一緒じゃないんですか?
先輩
返る値は同じでも、途中で何が実行されたかが違うんだ。既定値を作る処理がログを書いたり DB を読んだりするなら、その違いがそのまま不具合になるよ。

実行して確かめる

値がある Optional に orElse を使うと、使われない既定値を作るメソッドまで実行されます。次のコードで確かめました。

import java.util.Optional;

public class OrElseDemo {
    static String fallback() {
        System.out.println("  fallback() が呼ばれた");
        return "既定値";
    }
    public static void main(String[] args) {
        Optional<String> present = Optional.of("中身あり");
        System.out.println("[1] orElse(値あり)");
        System.out.println("  結果: " + present.orElse(fallback()));
        System.out.println("[2] orElseGet(値あり)");
        System.out.println("  結果: " + present.orElseGet(OrElseDemo::fallback));
        Optional<String> empty = Optional.empty();
        System.out.println("[3] orElseGet(空)");
        System.out.println("  結果: " + empty.orElseGet(OrElseDemo::fallback));
    }
}
OrElseDemo.java を javac --release 17 でコンパイルして実行した結果。[1] orElse(値あり)では fallback() が呼ばれたと出力されたうえで結果は中身あり、[2] orElseGet(値あり)では呼ばれず、[3] orElseGet(空)では呼ばれて結果は既定値になっている
OrElseDemo.java の実行結果(openjdk 21.0.11)。javac --release 17 で Java SE 17 の API に対してコンパイルした。値があるときも orElse の引数 fallback() が呼ばれている。

出力を1つずつ読みます。

  • [1] orElse(値あり):「fallback() が呼ばれた」が出ています。それでも結果は「中身あり」です。fallback() が返した「既定値」は使われずに捨てられています。
  • [2] orElseGet(値あり):「fallback() が呼ばれた」は出ません。値があるので Supplier は呼ばれていません。
  • [3] orElseGet(空):空なので Supplier が呼ばれ、結果は「既定値」です。

手元の JDK は 21 です。そのため javac --release 17 を付けて、Java SE 17 の API に対してコンパイルしました。2つのメソッドの説明が Java SE 17 の API ドキュメントでも同じであることは、次の章で引用して確かめます。

後輩
[1] で fallback() が動いたのに、結果が「中身あり」なのが不思議です。
先輩
「作ったけど使わなかった」んだよ。orElse は値を受け取るメソッドだから、呼ぶ前に引数の fallback() が実行される。そのあとで中身があると分かって、作った値は捨てられるんだ。

なぜ値があっても orElse の引数が実行されるのか

Java では、メソッドを呼ぶ前に引数の式がすべて評価されるからです。これは Optional の特別な仕様ではなく、Java のメソッド呼び出しそのもののルールです。

orElse(T other):受け取るのは「値」

Java SE 17 の API ドキュメントで、orElse の説明は「値が存在する場合は値を返し、そうでない場合は other を返します」です。引数 other の型は T、つまり値そのものです。

present.orElse(fallback()) と書くと、fallback() の戻り値を other として渡すことになります。渡すためには、先に fallback() を実行して値を作るしかありません。

Java の言語仕様(JLS)もこの順番を定めています。メソッド呼び出しの実行時の手順は5段階で、その2番目が「引数の式を評価する」です。呼ばれた側(orElse の中身)に制御が移るのは、最後の5番目です。

つまり、orElse の中で「値があるか」を調べる時点では、引数の評価はもう終わっています。

orElseGet(Supplier):受け取るのは「値の作り方」

orElseGet の引数は Supplier<? extends T> です。API ドキュメントの説明は「値が存在する場合は値を返し、そうでない場合は供給関数によって生成された結果を返します」です。

OrElseDemo::fallback や () -> fallback() と書いても、その時点では fallback() は動きません。渡しているのは「呼べば値を作る関数」です。orElseGet は値が無いと分かったときだけ、その関数を呼びます。

書き方 評価されるもの fallback() が動くとき
orElse(fallback()) fallback() の戻り値 呼び出しの前に必ず
orElseGet(() -> fallback()) ラムダ(関数)そのもの 空のときだけ
orElseGet(OrElseDemo::fallback) メソッド参照(関数)そのもの 空のときだけ

横にスクロールできます

ラムダ式で書いてもメソッド参照で書いても、結果は同じです。筆者の手元でもラムダ式の形で試し、値があるときは fallback() が呼ばれないことを確かめました。

後輩
じゃあ orElse(fallback()) を orElse(() -> fallback()) に書き換えればいいんですか?
先輩
それはコンパイルエラーになるよ。orElse の引数は T(この例なら String)だから、関数は渡せない。遅らせたいなら orElseGet に変える、が正解だね。

Java のバージョンで違いはあるか

Java SE 11 と Java SE 17 の API ドキュメントで、orElse と orElseGet の説明は同じです。どちらも Optional が追加された Java 8 からあるメソッドです。

関連するメソッドでは、引数なしの orElseThrow() が Java 10 で追加されました。別の Optional を代わりに返す or は Java 9 からです。

※この章の仕様は Optional の API ドキュメント(SE 17/SE 11)と Java 言語仕様(SE 17 版)15.12.4 より


どちらを使うか:使い分けの基準

既定値を作る処理が重い、または副作用があるなら orElseGet、定数や作成済みの変数なら orElse です。空をエラーとして扱いたいなら、どちらでもなく orElseThrow を使います。

既定値の中身 使うメソッド 理由
定数・リテラル("未設定"、0 など) orElse 評価されても何も起きない。短く読みやすい
作成済みの変数・フィールド orElse すでにある値を渡すだけ
DB・ファイル・外部 API からの取得 orElseGet 値があっても毎回読みに行くのを防ぐ
ログ出力・カウンタの更新など副作用のある処理 orElseGet 値があるときに副作用を起こさない
new で作るオブジェクト orElseGet 使わないオブジェクトを作らない
空ならエラーにしたい orElseThrow 既定値を作らず、例外で知らせる
空なら別の Optional を試したい or(Java 9 以降) 戻り値を Optional のまま扱える

横にスクロールできます

「迷ったら全部 orElseGet」でも動きは正しくなります。ただ、定数を返すだけの場所までラムダにすると、読み手は「何か重い処理があるのか」と身構えます。違いが出るのは引数に処理を書いたときだけなので、そこで orElseGet を選べば十分です。

落とし穴1:値があっても例外が出る

orElse の引数は必ず評価されるので、既定値を作る処理が例外を投げると、値がある Optional でも例外になります。筆者の手元で試すと、例外を投げるメソッドを orElse に渡した場合はその例外が出ました。同じメソッドを orElseGet に渡した場合は、値がそのまま返りました。

たとえば、設定ファイルが無いと例外を投げる「既定値の読み込み」を orElse に書いたとします。すると、値があるのに落ちる不具合になります。

落とし穴2:null を渡したとき

API ドキュメントでは、orElse の引数 other は「null も可」です。空の Optional に orElse(null) を使うと null が返ります。

orElseGet は「値が存在せず、供給関数が null の場合」に NullPointerException をスローします。値がある Optional なら、Supplier が null でもそのまま値が返ります。筆者の手元でも、この2通りの動きを確かめました。

後輩
じゃあ、DB から既定値を読む処理を orElse に書いていたら……。
先輩
値があるときも毎回 DB を読んでいる、ということになるね。結果は合っているから、テストでは気づきにくい。動きは正しいのに遅い、という形で見つかることが多いよ。

※この章のメソッドの説明は Java SE 17 の Optional の API ドキュメントより


Java Gold での問われ方

Java Gold では、Optional は Stream API の範囲で扱われます。根拠は Oracle 日本の Java SE 17 Programmer II(1Z0-826-JPN)の試験内容チェックリストです。「Java ストリーム API」の項目に「java.util.Optional クラスの使用」が載っています。

この論点は、コードの出力を選ばせる形と相性がよい題材です。次のような問いを想定して練習しておくと、本番で読み違えにくくなります。

  • 値がある Optional に orElse(メソッド呼び出し) を使ったとき、そのメソッドの中の println は出力されるか
  • 既定値を作るメソッドが何回呼ばれたか(カウンタの値)
  • orElseGet に null を渡したとき、例外になるか

練習用に、カウンタで呼ばれた回数を数えるコードを用意しました。出力を予想してから読み進めてください。

import java.util.Optional;

public class Quiz {
    static int n = 0;
    static String next() {
        n++;
        return "N" + n;
    }
    public static void main(String[] args) {
        Optional<String> a = Optional.of("A");
        Optional<String> b = Optional.empty();
        String r1 = a.orElse(next());
        String r2 = a.orElseGet(Quiz::next);
        String r3 = b.orElse(next());
        String r4 = b.orElseGet(Quiz::next);
        System.out.println(r1 + " " + r2 + " " + r3 + " " + r4 + " n=" + n);
    }
}

筆者の手元で実行した出力は A A N2 N3 n=3 でした。

  • r1:値があるので結果は A。ただし next() は実行され、n は1になる
  • r2:値があるので Supplier は呼ばれない。A で、n は1のまま
  • r3:空なので next() の結果が使われる。n は2になり、N2
  • r4:空なので Supplier が呼ばれる。n は3になり、N3

r1 の時点で n が増えていることに気づけるかが分かれ目です。「r1 は A だから next() は関係ない」と読むと、r3 を N1 と答えてしまいます。

同じ論点を試験の形式で解きたい方は、筆者が運営するエンジニア資格合格ラボのorElse と orElseGet の評価タイミングを問う演習問題をどうぞ。ラボの問題は AI で作成し、検証したものです。この1問を解けば合格できる、というものではありません。

受験する試験の時期に注意

Oracle 日本の配信終了一覧によると、1Z0-826-JPN の配信終了は2027年2月28日です。Java SE 25 に対応した日本語試験は、2026年11月下旬から配信開始予定です。

これから受ける方は、受ける試験の版と出題範囲を先に確かめてください。なお、英語試験の 1Z0-829 で受けると、日本の Java Gold(Oracle Certified Java Programmer, Gold SE 17)としては同時認定されません。Oracle 日本の試験ページにそう書かれています。

後輩
こういう「何回呼ばれた?」系の問題、どうやって解けばいいですか?
先輩
1行ずつ、引数を先に評価してからメソッドに入る、と順番どおりに追うことだね。特に orElse の行では「中身があるかを見る前に、引数はもう実行済み」と口に出して確認すると、取りこぼしにくいよ。

Optional 以外の Stream の落とし穴は、Java Gold のつまずきやすい単元にまとめています。Optional.of(null) など生成と取り出しの罠は、Java Gold のひっかけ問題パターンで扱っています。

※この章の試験情報は Oracle 日本の Java SE 17 Programmer II 試験ページと、試験の配信終了一覧より


よくある質問(FAQ)

orElse と orElseGet の違いを一言で言うと何ですか?

A. 引数がいつ評価されるかの違いです。orElse(T other) は値そのものを受け取るので、Optional に値があってもなくても、呼び出す前に引数が評価されます。orElseGet(Supplier) は値の作り方を受け取り、Optional が空のときだけ Supplier を呼びます。値があるときに返る結果はどちらも同じで、違いは引数の処理が実行されるかどうかです。

orElseGet はどんなときに使えばいいですか?

A. 既定値を作る処理が重いとき、または副作用があるときです。DB やファイルの読み込み、ログ出力、新しいオブジェクトの生成などを orElse の引数に書くと、値があっても毎回実行されます。定数や作成済みの変数を返すだけなら、評価されても困らないので orElse で十分です。空のときをエラーにしたいなら orElseThrow を使います。

orElseGet に null を渡すとどうなりますか?

A. Optional が空のときだけ NullPointerException になります。Java SE 17 の API ドキュメントには、値が存在せず供給関数が null の場合に NullPointerException をスローすると書かれています。値があるときは Supplier を呼ばないので、そのまま値が返ります。一方、orElse(null) は許されており、空なら null が返ります。

orElse と orElseGet の仕様は Java のバージョンで変わりましたか?

A. Java SE 11 と Java SE 17 の API ドキュメントで、2つのメソッドの説明は同じです。どちらも Optional が追加された Java 8 からあるメソッドです。引数なしの orElseThrow() は Java 10、別の Optional で代わりを用意する or は Java 9 で追加されました。受ける試験の版の API ドキュメントで確かめておくと安心です。

まとめ:orElse と orElseGet の違い

  • orElse は値を受け取る。 値があってもなくても、呼び出す前に引数が評価される。
  • orElseGet は値の作り方(Supplier)を受け取る。 空のときだけ呼ばれる。
  • 理由は Java の呼び出し規則。 メソッドに入る前に、引数の式はすべて評価される。
  • 使い分けは既定値の中身で決める。 重い処理・副作用・new なら orElseGet、定数なら orElse、空をエラーにするなら orElseThrow。
  • Java Gold では出力や呼ばれた回数を問う形に備える。 orElse の行で引数が実行済みであることを追う。

Java Gold の学習全体の進め方はJava Gold の勉強法を参考にしてください。


出典

(いずれも2026年10月12日に確認)


免責:本記事は、2026年10月12日時点で Oracle が公開している API ドキュメント・言語仕様・試験情報と、筆者の手元でコードを実行した結果にもとづく情報提供です。試験番号・配信終了日・出題範囲は Oracle により改定されることがあります。受験の前に、必ず公式サイトで最新の情報を確認してください。本記事は合格や特定の成果を保証するものではありません。