4 ответов:
использовать
mapесли функция возвращает нужный вам объект илиflatMapесли функция возвращаетOptional. Например:public static void main(String[] args) { Optional<String> s = Optional.of("input"); System.out.println(s.map(Test::getOutput)); System.out.println(s.flatMap(Test::getOutputOpt)); } static String getOutput(String input) { return input == null ? null : "output for " + input; } static Optional<String> getOutputOpt(String input) { return input == null ? Optional.empty() : Optional.of("output for " + input); }Оба оператора печати печатают одно и то же.
они оба принимают функцию от типа необязательного к чему-то.
карта применяет функцию "как есть" на необязательном у вас есть:
if (optional.isEmpty()) return Optional.empty(); else return Optional.of(f(optional.get()));что произойдет, если ваша функция-это функция от
T -> Optional<U>? Ваш результат теперьOptional<Optional<U>>!что это
flatMapО: если ваша функция уже возвращаетOptional,flatMapнемного умнее и не дважды обернуть его, возвращаяOptional<U>. Это композиция из двух функциональных идиом:mapиflatten.
Примечание: - ниже приведена иллюстрация функции map и flatmap, в противном случае необязательный в первую очередь предназначен для использования только в качестве возвращаемого типа.
как вы уже знаете, Optional-это своего рода контейнер, который может содержать или не содержать один объект, поэтому его можно использовать везде, где вы ожидаете нулевое значение(вы можете никогда не увидеть NPE, если используете Optional правильно). Например, если у вас есть метод, который ожидает объект person, который может быть nullable вы можете написать метод что-то вроде этого:
void doSome(Optional<Person> person){ /*and here you want to retrieve some property phone out of person you may write something like this: */ Optional<String> phone = person.map((p)->p.getPhone()); phone.ifPresent((ph)->dial(ph)); } class Person{ private String phone; //setter, getters }здесь вы вернули строковый тип, который автоматически завернут в необязательный тип.
Если класс person выглядел так, то есть телефон также не является обязательным
class Person{ private Optional<String> phone; //setter,getter }в этом случае вызов функции map обернет возвращаемое значение в необязательное и даст что-то вроде:
Optional<Optional<String>> //And you may want Optional<String> instead, here comes flatMap void doSome(Optional<Person> person){ Optional<String> phone = person.flatMap((p)->p.getPhone()); phone.ifPresent((ph)->dial(ph)); }PS; Никогда не вызывайте метод get (если вам нужно) по желанию, не проверяя его с помощью isPresent (), если вы не можете жить без возникновению исключительных ситуаций типа NullPointerException.
что помогло мне было взглянуть на исходный код двух функций.
карта - обертывает результат в необязательный.
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); //<--- wraps in an optional } }flatMap - возвращает ' raw ' объект
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Objects.requireNonNull(mapper.apply(value)); //<--- returns 'raw' object } }
Comments