Ответ
Оба метода предоставляют значение по умолчанию для пустого 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() для отложенных вычислений, особенно когда получение значения по умолчанию — дорогая операция.
Ответ 18+ 🔞
А, слушай, вот тебе реальная разница, которую половина народа на собесах проваливает, а потом в продакшене тормозит всё, как черепаха в патруле. Смотри, оба метода вроде как дают дефолтное значение, если в Optional нихуя нет, но тут, бля, вся соль в моменте, когда эта дефолтная хуйня вычисляется. И это, ёпта, напрямую бьёт по производительности, если не понимать.
orElse(T other)
Этот метод — как тот назойливый друг, который приходит в гости, даже если ты ему не звонил. Значение other вычисляется сразу, в момент вызова метода. Неважно, пустой там Optional или полный — ты уже за него заплатил по полной программе. Ну, ок, если там константа типа "N/A" — похуй. А если там вызов к базе данных?
Optional<String> foundName = findUserInCache(userId);
// Вот эта хуйня с запросом в БД выполнится ВСЕГДА, ёбаный насос!
// Даже если пользователь уже в кэше и всё ок.
String name = foundName.orElse(fetchUserFromDatabase(userId)); // Пиздец, а не оптимизация!
orElseGet(Supplier supplier)
А вот это уже хитрая жопа. Работает лениво, по требованию. Ты ему передаёшь не готовое значение, а Supplier — этакую обещашку, инструкцию "как достать значение, если приспичит". И выполнится эта инструкция только если Optional реально пустой. Для дорогих операций — просто манна небесная.
Optional<String> foundName = findUserInCache(userId);
// А вот этот вызов в базу случится ТОЛЬКО если в кэше пусто.
// Умно, экономно, мать его.
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(). Сэкономишь ресурсы, и система не будет орать как резаная, когда нагрузка подскочит. orElse() оставь для простых констант, где похуй.