switch expressions și yield în Java

switch folosit ca expresie care produce o valoare; yield returnează valoarea dintr-o ramură cu bloc.

Sintaxă
var rezultat = switch (valoare) {
    case 1 -> "unu";
    case 2, 3 -> "doi sau trei";
    default -> {
        var text = "altceva";
        yield text;
    }
};

Ce face switch expressions și yield

Din Java 14, switch poate fi o expresie: produce o valoare pe care o pui într-o variabilă, o returnezi sau o transmiți unei metode. Fiecare ramură case ... -> valoare; dă rezultatul, iar întregul switch se termină cu ; când e folosit într-o atribuire.

Un switch expression trebuie să fie exhaustiv: să acopere toate valorile posibile. Pentru numere și texte asta înseamnă default; pentru un enum sau o ierarhie sealed ajunge să tratezi toate cazurile, iar compilatorul verifică.

Când o ramură are nevoie de mai multe instrucțiuni, scrii un bloc între acolade și dai valoarea cu yield. yield este un cuvânt cheie contextual: are sens doar în switch expressions și se poate folosi și în forma cu două puncte (case 1: yield "unu";).

Exemple

Exemplul 1: Numele zilei

Rezultatul switch-ului este pus direct în variabila nume.

public class Main {
    public static void main(String[] args) {
        for (int zi = 1; zi <= 8; zi += 3) {
            String nume = switch (zi) {
                case 1 -> "luni";
                case 2 -> "marți";
                case 3 -> "miercuri";
                case 4 -> "joi";
                case 5 -> "vineri";
                case 6, 7 -> "weekend";
                default -> "necunoscut";
            };
            System.out.println(zi + " = " + nume);
        }
    }
}

Rezultat

1 = luni
4 = joi
7 = weekend

Exemplul 2: yield într-un bloc

Ramura pentru „transfer” calculează un comision în mai mulți pași și dă rezultatul cu yield.

public class Main {
    static double comision(String operatie, double suma) {
        return switch (operatie) {
            case "depunere" -> 0;
            case "retragere" -> 2.5;
            case "transfer" -> {
                double procent = suma * 0.005;
                double minim = 1.0;
                yield Math.max(procent, minim);
            }
            default -> throw new IllegalArgumentException("operație necunoscută: " + operatie);
        };
    }

    public static void main(String[] args) {
        System.out.println(comision("depunere", 500));
        System.out.println(comision("retragere", 500));
        System.out.println(comision("transfer", 1000));
        System.out.println(comision("transfer", 50));
        try {
            comision("împrumut", 100);
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }
    }
}

Rezultat

0.0
2.5
5.0
1.0
operație necunoscută: împrumut

Exemplul 3: Exhaustiv pe enum, fără default

Toate cele patru anotimpuri sunt tratate, deci default nu e necesar. Dacă adaugi un anotimp nou în enum, codul nu mai compilează până nu tratezi și cazul nou.

public class Main {
    enum Anotimp { PRIMAVARA, VARA, TOAMNA, IARNA }

    static String activitate(Anotimp a) {
        return switch (a) {
            case PRIMAVARA -> "plantăm flori";
            case VARA -> "mergem la mare";
            case TOAMNA -> "culegem struguri";
            case IARNA -> "facem oameni de zăpadă";
        };
    }

    public static void main(String[] args) {
        for (Anotimp a : Anotimp.values()) {
            System.out.println(a + ": " + activitate(a));
        }
    }
}

Rezultat

PRIMAVARA: plantăm flori
VARA: mergem la mare
TOAMNA: culegem struguri
IARNA: facem oameni de zăpadă

Greșeli frecvente

  • Lipsa lui default la un switch expression pe int sau String: the switch expression does not cover all possible input values.
  • Folosirea lui return în loc de yield într-un bloc al unui switch expression: nu compilează.
  • Uitarea lui ; după acolada finală când switch-ul este într-o atribuire.

Comenzi înrudite

  • switch, case și default: Alege ce cod se execută comparând o valoare cu mai multe constante case; default tratează orice altă valoare.
  • enum: enum declară un tip cu un set fix de valori cu nume (zilele săptămânii, stările unei comenzi), verificat de compilator.
  • Pattern matching (instanceof și switch): Pattern matching testează tipul (și forma) unui obiect și îi extrage părțile într-un singur pas, în instanceof sau în switch.
  • sealed, permits și non-sealed: O clasă sau interfață sealed își alege explicit subtipurile (permits); fiecare subtip este final, sealed sau non-sealed.