Java | Java 詳細・モダン文法:言語仕様詳細 – yield

Java Java
スポンサーリンク

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

ここでの流れはこうです。

  1. switch (score) が評価される
  2. 該当する case に入る
  3. その case が -> なら右辺の式が結果になる
  4. ブロック {} なら、その中の yield の値が結果になる
  5. 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 + " まずは基礎から見直しましょう。";
        }
    }
};
Java

default の中で if 文を使い、最後に yield でそれぞれのメッセージを返しています。
もし yield がなかったら、こういう「ちょっと複雑なロジックを持つ case」を switch 式の中に書くことができません。

ログを出したり、副作用を挟みたいとき

var result = switch (status) {
    case OK -> "成功";
    case ERROR -> {
        System.err.println("エラーが発生しました");
        yield "失敗";
    }
    default -> "不明";
};
Java

ERROR のときだけログを出してから値を返す、というような処理も、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、片方で intyield しようとすると、コンパイルエラーになります。

「全部のパターンで必ず 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 で同じ型を返す必要がある。」

タイトルとURLをコピーしました