Подтвердить что ты не робот

Правильное использование опции Optional.ifPresent()

Я пытаюсь понять метод ifPresent() API Optional в Java 8.

У меня простая логика:

Optional<User> user=...
user.ifPresent(doSomethingWithUser(user.get()));

Но это приводит к ошибке компиляции:

ifPresent(java.util.functionError:(186, 74) java: 'void' type not allowed here)

Конечно, я могу сделать что-то вроде этого:

if(user.isPresent())
{
  doSomethingWithUser(user.get());
}

Но это точно как загроможденная проверка null.

Если я изменю код на это:

 user.ifPresent(new Consumer<User>() {
            @Override public void accept(User user) {
                doSomethingWithUser(user.get());
            }
        });

Код становится грязнее, что заставляет меня думать о возврате к старой проверке null.

Любые идеи?

4b9b3361

Ответ 1

Optional<User>.ifPresent() принимает Consumer<? super User> Consumer<? super User> качестве аргумента. Вы передаете это выражение, тип которого void. Так что это не компилируется.

Потребитель должен быть реализован как лямбда-выражение:

Optional<User> user = ...
user.ifPresent(theUser -> doSomethingWithUser(theUser));

Или даже проще, используя ссылку на метод:

Optional<User> user = ...
user.ifPresent(this::doSomethingWithUser);

Это в основном то же самое, что

Optional<User> user = ...
user.ifPresent(new Consumer<User>() {
    @Override
    public void accept(User theUser) {
        doSomethingWithUser(theUser);
    }
});

Идея состоит в том, что doSomethingWithUser() метода doSomethingWithUser() будет выполняться только при наличии пользователя. Ваш код выполняет вызов метода напрямую и пытается передать его недействительный результат в ifPresent().

Ответ 2

В дополнение к ответу @JBNizet, мой общий пример использования ifPresent - объединить .isPresent() и .get():

Старый способ:

Optional opt = getIntOptional();
if(opt.isPresent()) {
    Integer value = opt.get();
    // do something with value
}

Новый способ:

Optional opt = getIntOptional();
opt.ifPresent(value -> {
    // do something with value
})

Для меня это более интуитивно понятно.

Ответ 3

Используйте flatMap. Если значение присутствует, flatMap возвращает последовательный поток, содержащий только это значение, в противном случае возвращает пустой поток. Поэтому нет необходимости использовать ifPresent(). Пример:

list.stream().map(data -> data.getSomeValue).map(this::getOptinalValue).flatMap(Optional::stream).collect(Collectors.toList());

Ответ 4

Вы можете использовать ссылку на метод следующим образом:

user.ifPresent(ClassNameWhereMethodIs::doSomethingWithUser);

Метод ifPresent() получает объект Consumer в качестве параметра и (из JavaDoc): "Если значение присутствует, вызовите указанного потребителя со значением". Значение это ваша переменная user.

Или, если этот метод doSomethingWithUser находится в классе User и он не является static, вы можете использовать ссылку на метод следующим образом:

user.ifPresent(this::doSomethingWithUser);

Ответ 5

Зачем писать сложный код, если вы можете сделать его простым?

Действительно, если вы абсолютно собираетесь использовать класс Optional, самый простой код - это то, что вы уже написали...

if (user.isPresent())
{
    doSomethingWithUser(user.get());
}

Этот код имеет преимущества

  1. удобочитаемый
  2. легко отлаживать (точка останова)
  3. не сложно

Тот факт, что Oracle добавил класс Optional в Java 8, не означает, что этот класс должен использоваться во всех ситуациях.