Условные конструкции

if / else

if выбирает ветку по выражению типа boolean:

if (temperature < 0) {
    state = "ICE";
} else if (temperature == 0) {
    state = "BOUNDARY";
} else {
    state = "WATER";
}

Java не преобразует число или ссылку в boolean. Условия лучше строить из названных предикатов и избегать глубокой вложенности.

Короткое замыкание

&& и || вычисляют правую часть только при необходимости:

if (user != null && user.isActive()) {
    allow(user);
}

Операторы & и | применимы и к boolean, но вычисляют обе стороны. Они нужны реже; побочные эффекты в условиях затрудняют чтение.

Тернарный оператор

Тернарное выражение возвращает значение:

String label = count == 0 ? "empty" : "items=" + count;

Оно удобно для простого выбора. Вложенные тернарные выражения обычно лучше заменить if или отдельным методом. Тип результата определяется обеими ветками и правилами преобразования типов.

switch

Классический switch использует переход к метке и требует break, чтобы не провалиться дальше:

switch (status) {
    case NEW:
        initialize();
        break;
    case READY:
        execute();
        break;
    default:
        reject();
}

Современная форма со стрелками не имеет случайного fall-through и может быть выражением:

int priority = switch (status) {
    case NEW -> 10;
    case READY -> 1;
    case DONE -> 100;
};

Для enum исчерпывающий switch без default полезен: при добавлении константы компилятор потребует обновить выражение.

Блок может вернуть значение через yield:

String message = switch (status) {
    case NEW -> "created";
    case READY -> {
        audit(status);
        yield "available";
    }
    case DONE -> "finished";
};

switch над null выбрасывает NullPointerException, если современный pattern switch не содержит явный case null. Границу null лучше определить в самом контракте, а не случайно доверять default.

Pattern matching

Проверку типа можно совместить с объявлением переменной:

if (value instanceof String text && !text.isBlank()) {
    System.out.println(text.length());
}

Переменная text доступна только там, где компилятор доказал успешность проверки.

Ловушки

  • Случайный fall-through в классическом switch.
  • Boolean со значением null в условии: unboxing приведёт к NullPointerException.
  • Побочные эффекты в правой части &&/||, выполнение которых зависит от левой.
  • Сравнение строк через == в условии.
  • default, который скрывает необходимость обработать новую константу enum.
  • Слишком сложное условие без выделенных именованных предикатов.

Вопросы на собеседовании

  1. Чем && отличается от & для boolean?
  2. Что такое fall-through в switch?
  3. Чем switch-выражение отличается от классического switch-оператора?
  4. Что произойдёт при if (nullableBoolean) и значении null?
  5. Когда отсутствие default в switch по enum полезно?
  6. Как pattern matching для instanceof влияет на область видимости переменной?

Связанные заметки

Переменные и типы данных Java · Преобразование типов Java · Работа со строковыми данными · Работа с исключениями в Java