JavaMiddleTechnical
В чём разница между Optional.orElse() и Optional.orElseGet()?
orElse(value) вычисляет запасное значение всегда, даже когда Optional не пуст; orElseGet(supplier) вычисляет его лениво — только при пустом Optional. Для дорогих операций (БД, создание объекта) используйте orElseGet.
Optional.orElse() vs Optional.orElseGet()
Оба метода возвращают значение из Optional, если оно есть, и «запасное» значение, если Optional пуст. Ключевое различие — момент вычисления этого запасного значения.
orElse(T other)принимает уже вычисленное значение. Выражениеotherвычисляется всегда, даже когда Optional не пуст.orElseGet(Supplier<? extends T> supplier)принимает лямбду. Supplier вызывается только тогда, когда Optional пуст (lazy evaluation).
Демонстрация разницы
import java.util.Optional;
public class OrElseDemo {
static String expensive() {
System.out.println("expensive() called");
return "fallback";
}
public static void main(String[] args) {
Optional<String> present = Optional.of("real value");
// orElse: expensive() вызывается ВСЕГДА
String a = present.orElse(expensive());
// Вывод: "expensive() called"
System.out.println(a); // real value
System.out.println("---");
// orElseGet: expensive() вызывается ТОЛЬКО когда Optional пуст
String b = present.orElseGet(() -> expensive());
// Вывод: (ничего — supplier не вызван)
System.out.println(b); // real value
System.out.println("---");
Optional<String> empty = Optional.empty();
String c = empty.orElse(expensive()); // expensive() called
String d = empty.orElseGet(() -> expensive()); // expensive() called
System.out.println(c + " / " + d); // fallback / fallback
}
}
Правило выбора
- Если запасное значение — это уже готовый литерал или легковесная константа (
orElse("default"),orElse(Collections.emptyList())) — используйтеorElse. - Если запасное значение дорого создавать (запрос к БД, создание нового объекта, форматирование строки) — всегда используйте
orElseGet. - Для исключений существует отдельный метод:
orElseThrow(IllegalArgumentException::new)— не путайте сorElseGet.
Практический пример: кэш пользователей
import java.util.Optional;
import java.util.Map;
public class UserCache {
private final Map<Long, User> cache;
private final UserRepository repo;
public User findUser(long id) {
// ПРАВИЛЬНО: БД запрашивается только при cache miss
return Optional.ofNullable(cache.get(id))
.orElseGet(() -> repo.findById(id));
// НЕПРАВИЛЬНО: repo.findById(id) вызывается всегда!
// return Optional.ofNullable(cache.get(id))
// .orElse(repo.findById(id));
}
}
Подводные камни
- Неожиданные side effects в orElse. Если «запасное» выражение выполняет запись в БД или логирует, оно сработает даже когда Optional не пуст — это почти всегда ошибка.
- NullPointerException внутри orElse. Если выражение в
orElse(expr)само возвращает null, вы получите null из non-empty Optional — удивительный результат. - Путаница с orElseThrow.
orElseThrow()без аргументов бросаетNoSuchElementException;orElseThrow(Supplier)— любое исключение по Supplier. Не передавайте готовый экземпляр исключения (этоorElse-семантика), используйте Supplier. - Wrapping null в Optional.of.
Optional.of(null)бросает NPE немедленно; используйтеOptional.ofNullable. - Optional в полях классов. Oracle рекомендует Optional только как возвращаемый тип метода, не как поле сущности или параметр конструктора — сериализация и JPA не работают корректно с Optional-полями.
- orElseGet не обрабатывает исключения. Checked exception из лямбды Supplier нужно обернуть или пробросить через unchecked.
Common mistakes
- Путать термин «optional or else get» с соседним механизмом Java.
- Не называть границу lifecycle, transaction, thread или request для «optional or else get».
- Игнорировать production-эффекты «optional or else get»: latency, SQL shape, memory, security или observability.
What the interviewer is testing
- Попросить объяснить механизм «optional or else get» на минимальном примере.
- Проверить, видит ли кандидат failure mode и диагностику для «optional or else get».
- Уточнить, какие настройки или API меняют «optional or else get» в реальном сервисе.