yield を一言でいうと
yield は、switch「式」の中で
「この case ブロックから“この値を返す”」
とコンパイラに伝えるためのキーワードです。
return が「メソッドから値を返す」のに対して、yield は「switch 式の中の case ブロックから値を返す」ために使います。
なぜ yield が必要になるのか
シンプルな switch 式なら → だけで足りる
まず、基本の switch 式を思い出しましょう。
var label = switch (score) {
case 100 -> "満点";
case 90, 80 -> "よくできました";
default -> "がんばりましょう";
};
Javaここでは、-> の右側が 1 行の式 なので、そのまま「switch 式の結果」として使えます。
この場合、yield は不要です。
複数行の処理をしたいときに困る
でも、こういうことをしたくなる場面があります。
var message = switch (score) {
case 100 -> "満点";
case 90, 80 -> "よくできました";
default -> {
// ここでちょっと複雑な処理をしたい…
var base = "点数は " + score + " です";
// その結果を switch 式の値として返したい
}
};
Java{ ... } でブロックを書いた瞬間、-> の右側は「式」ではなく「文のブロック」になります。
そのままでは「このブロック全体として、どの値を switch 式に返すのか」が分かりません。
そこで登場するのが yield です。
yield の基本的な使い方
ブロックの中で「この値を返す」と書く
先ほどの例を yield を使って完成させると、こうなります。
var message = switch (score) {
case 100 -> "満点";
case 90, 80 -> "よくできました";
default -> {
var base = "点数は " + score + " です";
var suffix = score >= 60 ? "(合格)" : "(不合格)";
yield base + suffix; // ← これが switch 式の“結果”になる
}
};
Javaポイントはここです。
default -> { ... }の{ ... }は「ブロック」- そのブロックの中で
yield 値;と書く - その
値が「この case の結果」として switch 式全体に返される
return と違って、「メソッドから抜ける」のではなく、「この switch 式の“この case ブロック”から値を返す」だけです。
yield と return の違いを感覚でつかむ
return は「メソッドの出口」、yield は「switch 式の出口」
イメージとしては、こうです。
return:メソッド全体の出口yield:switch 式の中の「その case ブロックの出口」
例えば、こんなメソッドを考えます。
String judge(int score) {
return switch (score) {
case 100 -> "満点";
case 90, 80 -> "よくできました";
default -> {
var msg = "点数は " + score + " です";
yield msg; // switch 式の“結果”を返す
}
}; // ← この switch 式全体の結果が、メソッドの return になる
}
Javaここでの流れはこうです。
switch (score)が評価される- 該当する
caseに入る - その case が
->なら右辺の式が結果になる - ブロック
{}なら、その中のyieldの値が結果になる - switch 式全体の結果が
returnでメソッドから返される
yield はあくまで「switch 式の中の話」であって、メソッドの外には出ません。
yield が本領発揮するパターン
条件分岐が少し複雑なとき
例えば、「点数に応じてメッセージを返すけど、60 点未満のときだけ詳しい説明をつけたい」というケース。
var message = switch (score) {
case 100 -> "満点!";
case 90, 80 -> "よくできました";
case 70, 60 -> "合格です";
default -> {
var base = "不合格です(点数: " + score + ")";
if (score >= 50) {
yield base + " 惜しい!あと少し。";
} else {
yield base + " まずは基礎から見直しましょう。";
}
}
};
Javadefault の中で if 文を使い、最後に yield でそれぞれのメッセージを返しています。
もし yield がなかったら、こういう「ちょっと複雑なロジックを持つ case」を switch 式の中に書くことができません。
ログを出したり、副作用を挟みたいとき
var result = switch (status) {
case OK -> "成功";
case ERROR -> {
System.err.println("エラーが発生しました");
yield "失敗";
}
default -> "不明";
};
JavaERROR のときだけログを出してから値を返す、というような処理も、yield があるから自然に書けます。
switch 式と yield の「型」の話
switch 式は「式」なので、型がある
switch を「式」として使う以上、その結果には 型 があります。
var message = switch (score) {
case 100 -> "満点";
default -> "その他";
};
Javaこの場合、switch 式全体の型は String です。
yield を使うときも、すべての case で同じ型を返さなければなりません。
var value = switch (flag) {
case true -> {
yield 1; // int
}
case false -> {
yield 2; // int
}
// どちらも int なので OK
};
Javaもし片方で String、片方で int を yield しようとすると、コンパイルエラーになります。
「全部のパターンで必ず yield する」ことが必要
ブロックを使った case では、必ずどの経路でも yield に到達する必要があります。
var msg = switch (score) {
default -> {
if (score >= 60) {
yield "合格";
}
// ここで何も yield せずにブロックを抜けようとするとコンパイルエラー
}
};
Javaこの場合、else 側でも yield しないといけません。
default -> {
if (score >= 60) {
yield "合格";
} else {
yield "不合格";
}
}
Java「switch 式は必ず値を返す」「ブロックの中でも必ずどこかで yield する」というルールが、型安全性を守っています。
まとめ:yield を自分の言葉で説明するなら
あなたの言葉で yield を説明するなら、こうです。
「yield は、switch“式”の中の case ブロックから値を返すためのキーワード。-> の右側が 1 行の式ならそのままでいいけれど、
ブロック {} の中で複数行の処理をしたいときは、
最後に yield 値; と書いて“この case の結果はこれ”とコンパイラに教える。return がメソッドの出口なら、yield は case ブロックの出口。
すべての経路で必ず何かを yield し、全ての case で同じ型を返す必要がある。」
