В чем разница между orElse() и orElseGet() в Java Optional?

«В чем разница между orElse() и orElseGet() в Java Optional?» — вопрос из категории Java, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Оба метода предоставляют значение по умолчанию для пустого Optional, но различаются моментом вычисления этого значения, что напрямую влияет на производительность.

orElse(T other)

  • Вычисляет значение other немедленно, в момент вызова метода, независимо от того, пуст Optional или нет.
  • Подходит для простых, дешевых констант или предварительно вычисленных значений.
Optional<String> foundName = findUserInCache(userId);
// Дорогой вызов БД произойдет ВСЕГДА, даже если пользователь найден в кэше
String name = foundName.orElse(fetchUserFromDatabase(userId)); // Неоптимально!

orElseGet(Supplier supplier)

  • Вычисляет значение лениво, только если Optional действительно пуст.
  • Принимает Supplier — функциональный интерфейс, код которого выполняется по требованию.
  • Предпочтительный выбор для ресурсоемких операций (запросы к БД, сетевые вызовы, сложные вычисления).
Optional<String> foundName = findUserInCache(userId);
// Вызов fetchUserFromDatabase произойдет ТОЛЬКО если кэш пуст
String name = foundName.orElseGet(() -> fetchUserFromDatabase(userId)); // Оптимально

Ключевое отличие на примере

public String getDefaultValue() {
    System.out.println("Вычисляю значение по умолчанию...");
    return "Default";
}

Optional<String> fullOpt = Optional.of("Actual Value");
Optional<String> emptyOpt = Optional.empty();

// С orElse()
String result1 = fullOpt.orElse(getDefaultValue()); // Выведет: "Вычисляю значение по умолчанию..."
// result1 = "Actual Value", но побочный эффект выполнен!

String result2 = emptyOpt.orElse(getDefaultValue()); // Выведет: "Вычисляю значение по умолчанию..."
// result2 = "Default"

// С orElseGet()
String result3 = fullOpt.orElseGet(() -> getDefaultValue()); // Ничего не выведет!
// result3 = "Actual Value", вычисления не было

String result4 = emptyOpt.orElseGet(() -> getDefaultValue()); // Выведет: "Вычисляю значение по умолчанию..."
// result4 = "Default"

Вывод: Используйте orElseGet() для отложенных вычислений, особенно когда получение значения по умолчанию — дорогая операция.