Как заглянуть в опцию?

Я хочу использовать свободный api Optional и применить к нему два Consumer.

Мне снится что-то вроде этого:

Optional.ofNullable(key)
    .map(Person::get)
    .ifPresent(this::printName)
    .ifPresent(this::printAddress); // not compiling, because ifPresent is void

Как применить несколько Consumer к Optional?

Ответ 1

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

ofNullable(key)
    .map(Person::get)
    .map(x -> {printName(x);return x;})
    .map(x -> {printAddress(x);return x;});

Ответ 2

Хотя это может показаться не очень элегантным, я бы просто объединил оба метода в одну lambda и передал это ifPresent:

ofNullable(key)
    .map(Person::get)
    .ifPresent(x -> {printName(x); printAddress(x);});

В качестве альтернативы вы также можете использовать andThen для andThen нескольких потребителей, хотя для этого вам потребуется указать ссылку на метод Consumer, которая также не очень элегантна.

ofNullable(key)
    .map(Person::get)
    .ifPresent(((Consumer) this::printName).andThen(this::printAddress));

Ответ 3

Здесь, как вы можете реализовать отсутствующий метод peek для параметра Optional:

<T> UnaryOperator<T> peek(Consumer<T> c) {
    return x -> {
        c.accept(x);
        return x;
    };
}

Использование:

Optional.ofNullable(key)
    .map(Person::get)
    .map(peek(this::printName))
    .map(peek(this::printAddress));

Ответ 4

Возможно, что-то вроде этого:

Optional.ofNullable(key)
        .map(Person::get)
        .ifPresent(combine(this::printAddress, this::printWish));

где combine:

public <T> Consumer<T> combine(Consumer<T>... cs) {
  return x -> Stream.of(cs).peek(c -> c.accept(x)).close();
}

Ответ 5

С новым потоковым методом в Дополнительном API, начиная с JDK9, вы можете вызвать stream метод для преобразования из Optional<T> в Stream<T> которое затем позволяет peek а затем, если вы хотите вернуться к Optional<T> просто вызовите findFirst() или findAny().

пример в вашем случае:

Optional.ofNullable(key)
        .map(Person::get) // Optional<Person>
        .stream() // Stream<Person>
        .peek(this::printName)
        .peek(this::printAddress)
        ...

Ответ 6

Альтернатива Java 8 (map + orElseGet):

Optional.ofNullable(key)
        .map(Person::get) // Optional<Person>
        .map(Stream::of)  // Optional<Stream<Person>>
        .orElseGet(Stream::empty) // Stream<Person>
        .peek(this::printName)
        .peek(this::printAddress)
        .findAny();