Switch expressions (Java 14)

В классической форме switch — это оператор (statement): он что-то делает, но ничего не возвращает. С Java 14 (JEP 361) switch стал ещё и выражением (expression) — он может возвращать значение, которое присваивается переменной или возвращается из метода.

Вместе с этим появился короткий стрелочный синтаксис (case L -> ...), который автоматически выполняет break после каждой ветки. Это убирает классическую ошибку «забыл break и провалился в следующий case».

Минимальная версия: Java 14.

Синтаксис

// Стрелочная форма (без fall-through)
var result = switch (value) {
    case A, B -> "a or b";
    case C    -> "c";
    default   -> "other";
};

// С блоком и yield
var x = switch (value) {
    case 1 -> 100;
    case 2 -> {
        int tmp = 50;
        yield tmp * 2;
    }
    default -> 0;
};

Зачем нужно

  • switch возвращает значение — не нужно временной переменной.

  • Стрелочная форма не имеет fall-through — меньше багов.

  • Несколько меток через запятую: case 1, 2, 3 ->.

  • Компилятор требует обработать все случаи (exhaustive).

Пример 1. Switch как выражение

public class SwitchExpr {
    public static void main(String[] args) {
        int day = 3;
        String name = switch (day) {
            case 1 -> "Понедельник";
            case 2 -> "Вторник";
            case 3 -> "Среда";
            case 4 -> "Четверг";
            case 5 -> "Пятница";
            case 6, 7 -> "Выходной";
            default -> "Неверный день";
        };
        System.out.println("День " + day + ": " + name);
    }
}

Output:

День 3: Среда

Пример 2. Несколько меток через запятую

public class SwitchMulti {
    public static String season(int month) {
        return switch (month) {
            case 12, 1, 2  -> "Зима";
            case 3, 4, 5   -> "Весна";
            case 6, 7, 8   -> "Лето";
            case 9, 10, 11 -> "Осень";
            default -> throw new IllegalArgumentException("Неверный месяц: " + month);
        };
    }

    public static void main(String[] args) {
        for (int m : new int[] {1, 4, 7, 10}) {
            System.out.println(m + " -> " + season(m));
        }
    }
}

Output:

1 -> Зима
4 -> Весна
7 -> Лето
10 -> Осень

Пример 3. Блок с yield

public class SwitchYield {
    public static int complexLogic(int x) {
        return switch (x) {
            case 0 -> 0;
            case 1 -> 1;
            default -> {
                int square = x * x;
                int doubled = square * 2;
                yield doubled + 1;   // возвращает значение из блока
            }
        };
    }

    public static void main(String[] args) {
        System.out.println("0 -> " + complexLogic(0));
        System.out.println("1 -> " + complexLogic(1));
        System.out.println("3 -> " + complexLogic(3));
        System.out.println("5 -> " + complexLogic(5));
    }
}

Output:

0 -> 0
1 -> 1
3 -> 19
5 -> 51

Пример 4. Switch по String

public class SwitchString {
    public static int pinFor(String component) {
        return switch (component) {
            case "trig"        -> 3;
            case "echo"        -> 7;
            case "servo"       -> 9;
            case "ir"          -> 17;   // A3
            case "bt-rx"       -> 10;
            case "bt-tx"       -> 11;
            default -> throw new IllegalArgumentException("Неизвестный компонент: " + component);
        };
    }

    public static void main(String[] args) {
        String[] parts = {"trig", "echo", "servo", "bt-rx"};
        for (String p : parts) {
            System.out.println(p + " -> D" + pinFor(p));
        }
    }
}

Output:

trig -> D3
echo -> D7
servo -> D9
bt-rx -> D10

Пример 5. Switch по enum (exhaustive)

public class SwitchEnum {
    enum Direction { FORWARD, BACKWARD, LEFT, RIGHT, STOP }

    public static String command(Direction d) {
        // default не нужен — все варианты enum покрыты
        return switch (d) {
            case FORWARD  -> "M F";
            case BACKWARD -> "M B";
            case LEFT     -> "M L";
            case RIGHT    -> "M R";
            case STOP     -> "M S";
        };
    }

    public static void main(String[] args) {
        for (Direction d : Direction.values()) {
            System.out.println(d + " -> " + command(d));
        }
    }
}

Output:

FORWARD -> M F
BACKWARD -> M B
LEFT -> M L
RIGHT -> M R
STOP -> M S

Пример 6. Старый vs новый стиль

public class SwitchOldVsNew {
    // Старый стиль: оператор с break
    public static String oldStyle(int n) {
        String result;
        switch (n) {
            case 1:
                result = "один";
                break;
            case 2:
                result = "два";
                break;
            default:
                result = "много";
        }
        return result;
    }

    // Новый стиль: выражение
    public static String newStyle(int n) {
        return switch (n) {
            case 1 -> "один";
            case 2 -> "два";
            default -> "много";
        };
    }

    public static void main(String[] args) {
        for (int n : new int[] {1, 2, 5}) {
            System.out.println(n + ": old=" + oldStyle(n) + ", new=" + newStyle(n));
        }
    }
}

Output:

1: old=один, new=один
2: old=два, new=два
5: old=много, new=много

Подводные камни

Предупреждение

  • В стрелочной форме break использовать нельзя — после стрелки идёт одно выражение или блок.

  • В блоке возвращайте значение через yield, а не через return (return выйдет из метода целиком).

  • Если switch используется как выражение, он обязан быть exhaustive: либо default, либо покрытие всех вариантов enum/sealed.

  • Смешивать case A: и case A -> в одном switch нельзя.

  • case null (Java 21) нужно объявлять явно, иначе NullPointerException.

Совет

Если switch имеет более 2-3 веток и возвращает значение — используйте expression-форму. Код становится короче и безопаснее.

См. также

Примечание

Материал основан на официальной документации Oracle Java SE (docs.oracle.com/en/java/javase) и спецификации JEP 361 (openjdk.org/jeps/361), распространяемой под лицензией Oracle Free Documentation License. Тексты и примеры написаны заново для AlashEd Wiki.