it-swarm.com.ru

Правильное использование 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.

Есть идеи?

55
rayman

Optional<User>.ifPresent() принимает 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() будет выполняться только при наличии пользователя. Ваш код выполняет вызов метода напрямую и пытается передать результат void в ifPresent().

96
JB Nizet

В дополнение к ответу @ 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
})

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

8
cst1992

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

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

Вы должны использовать это так:

user.ifPresent(ClassNameWhereMethodIs::doSomethingWithUser);

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

3
Aleksandr Podkutin

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

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

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

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

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

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

1
schlebe