Optional(orElse の即時評価 vs orElseGet の遅延)難易度 高無料
次のコードの出力として正しいものを選べ。
1 import java.util.*;
2 public class Q7 {
3 static String supply() {
4 System.out.println("called");
5 return "X";
6 }
7 public static void main(String[] a) {
8 Optional<String> o = Optional.of("V");
9 String r1 = o.orElse(supply());
10 String r2 = o.orElseGet(() -> supply());
11 System.out.println(r1 + " " + r2);
12 }
13 }
- A
called改行V V - B
V V("called" は出力されない) - C
called改行called改行V V - D
called改行X X
正解・解説・誤答理由・ひっかけを見る▼ open
✓ 正解:AAI作成・独立検証済
解説
鍵は引数がいつ評価されるか。
各誤答が違う理由
orElse(other) の引数 other はふつうのメソッド呼び出しの引数なので、
orElse を呼ぶ前に必ず評価される(Optional が値を持っていて使われなくても評価される)。
よって o.orElse(supply()) は supply() を実行し("called" が出力される)、
その戻り "X" は捨てられ、Optional の中身 "V" が r1 になる。
orElseGet(supplier) は Supplier を受け取り、Optional が空のときだけ get() を呼ぶ(遅延評価)。
ここは値が有るので ラムダは呼ばれない("called" は増えない)。r2 は "V"。
したがって出力は "called"(1回・orElse 由来)に続いて V V。
- B
orElse(supply())の引数は Optional が空でなくても必ず評価される。よって "called" が1回出る。 - C
orElseGetのラムダは Optional が空のときだけ実行される。ここは値が有るので呼ばれず、"called" は1回だけ。 - D
orElse/orElseGetは Optional が空のときだけ代替値を返す。値"V"が有るのでr1・r2とも"V"("X" は使われない)。
ひっかけ: 「値が有るなら or〜 の中身は使われない=評価もされない」という思い込み。
orElse は常に引数を評価する(副作用や重い処理があると無駄・危険)。だからデフォルト生成にコストがある時は orElseGet を使うのが定石。実機確認の答え合わせ
出力: called V V
公式ドキュメント・関連Optional.orElse / orElseGet(SE17 API)↗
AIが作成し、独立した検証を経た解説です(有資格者による監修は経ていません)