В чем разница между Optional.orElse и Optional.orElseGet и когда использовать каждый
Что проверяют
Замечаете ли вы, что аргумент вычисляется до вызова метода. Это классическая ловушка, которая в проде выглядит как лишние запросы к базе.
Как отвечать
orElse(T other) принимает готовое значение. Java вычисляет аргументы до вызова метода, поэтому выражение внутри orElse выполняется всегда, даже когда значение в Optional есть и результат не понадобится.
orElseGet(Supplier<T>) принимает функцию и вызывает её только тогда, когда значения нет.
// Запрос к базе уйдёт даже если пользователь найден в кеше
User u1 = cache.find(id).orElse(repository.load(id));
// Запрос уйдёт только при промахе кеша
User u2 = cache.find(id).orElseGet(() -> repository.load(id));Отсюда правило: константа или уже вычисленное значение это orElse, любой вызов метода, создание объекта или обращение к внешней системе это orElseGet.
Полезно назвать соседей из того же API: orElseThrow(Supplier) тоже ленивый, поэтому исключение создаётся только при необходимости (а создание исключения со стектрейсом недёшево); or(Supplier<Optional<T>>) из Java 9 позволяет подставить другой Optional; ifPresentOrElse закрывает случай «сделать одно или другое».
Дополнительно стоит помнить общие правила Optional: он задуман как тип возвращаемого значения, а не как поле класса или параметр метода, и он не сериализуется.
Где спотыкаются
Пишут orElse(new ArrayList<>()) и считают это безобидным. Объект создаётся на каждый вызов, в горячем коде это заметно.
Прячут в orElse вызов с побочным эффектом, и он выполняется даже тогда, когда не должен.
Проверяют optional.isPresent() и затем get(), хотя весь смысл типа в том, чтобы этого не делать.