У меня были проблемы с оценкой дополнительных возможностей Java. Рассмотрим следующий тест:
@Test
public void test() {
System.out.println("GOT STRING: " + first().orElse(second()));
}
private Optional<String> first() {
System.out.println("Evaluating first");
return Optional.of("STRING OPTIONAL");
}
private String second() {
System.out.println("Evaluating second");
return "SECOND STRING";
}
Я ожидаю, что, поскольку first () возвращает непустой Optional, второй не оценивается. Но на самом деле результат такой:
Evaluating first
Evaluating second
GOT STRING: STRING OPTIONAL
Пробуем использовать функцию, используемую в orElse, в тесте:
@Test
public void test2() {
System.out.println("GOT STRING: " + (first() != null ? "FIRST IS NOT NULL" : second()));
}
Выход:
Evaluating first
GOT STRING: FIRST IS NOT NULL
Почему оценивается второй вариант? Вроде плохо?
3 ответа
Почему оценивается второй вариант?
Потому что вы вызываете метод second()
, чтобы предоставить значение в качестве аргумента для orElse()
. Значение аргумента будет проигнорировано (потому что у вас уже есть значение), но это не значит, что его не нужно указывать.
В основном это код:
first().orElse(second())
Эквивалентно:
Optional<String> tmp1 = first();
Optional<String> tmp2 = second();
Optional<String> result = tmp1.orElse(tmp2);
Здесь нет ничего особенного в необязательном порядке - именно так в Java работает оценка аргументов всегда .
Обратите внимание, что это большая разница между конструкцией library (orElse
) и конструкцией оператора условия language (?:
), которая оценивает только либо второй или третий операнд, но не оба одновременно.
Как упоминал Артур, если вы хотите отложить вызов second()
, вам нужно использовать orElseGet
, где переданный вами аргумент не является значением, которое следует использовать, если first
не имеет один, но вызов, который нужно сделать, чтобы получить значение.
Поскольку вызов second()
передается как параметр методу orElse
, и параметры быстро оцениваются в Java.
Если вам нужно предоставить поставщика или избежать нетерпеливого исполнения, вы можете использовать orElseGet
, который ожидает Supplier
optional.orElseGet(()->second()))
Он оценивается, потому что вы передаете значение second()
по значению, а не просто передаете ссылку на саму функцию. Вам нужно сделать одно из следующих
System.out.println("GOT STRING: " + first().orElseGet(() ->second()));
System.out.println("GOT STRING: " + first().orElseGet(this::second));
Отложить оценку до тех пор, пока она действительно не понадобится.
Похожие вопросы
Новые вопросы
java
Java — это высокоуровневый объектно-ориентированный язык программирования. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег часто используется вместе с другими тегами для библиотек и/или фреймворков, используемых разработчиками Java.