@AlexisC. Ваша ссылка о карте Stream и flatMap, а не как опция.
Eran
1
@Eran Это не имеет значения, если вы понимаете, как работает map / flatMap, для потока это или нет, то же самое для Optional. Если операция поняла, как это работает для Stream, ему не следует задавать этот вопрос. Концепция такая же.
Алексис С.
2
@AlexisC. На самом деле, нет. FlatMap от Optional имеет мало общего с flatMap от Stream.
Eran
1
@Eran Я говорю о концептуальной разнице между картой и flatMap, я не делаю однозначное соответствие между Stream#flatMapи Optional#flatMap.
Алексис С.
Ответы:
166
Используйте, mapесли функция возвращает нужный вам объект или flatMapесли функция возвращает Optional. Например:
publicstaticvoid main(String[] args){Optional<String> s =Optional.of("input");System.out.println(s.map(Test::getOutput));System.out.println(s.flatMap(Test::getOutputOpt));}staticString getOutput(String input){return input ==null?null:"output for "+ input;}staticOptional<String> getOutputOpt(String input){return input ==null?Optional.empty():Optional.of("output for "+ input);}
Вопрос: будет ли [flat]Mapкогда-либо вызывать функцию отображения с input == null? OptionalНасколько я понимаю, сортировка, если она отсутствует, [JavaDoc] ( docs.oracle.com/javase/8/docs/api/java/util/… ), кажется, подтверждает это: « Если значение присутствует, примените .. . "
@BoristheSpider да, вы правы. Я пытался ответить на ваш вопрос, но думаю, что сделал его еще более неясным: концептуально Optional.ofNullable (null) НЕ должен быть пустым, но на практике он считается, и поэтому map / flatmap не выполняются.
Диего Мартиноя
1
Я думаю, что входные данные никогда не должны быть нулевыми ни в getOutputOpt, ни в getOutput
DanyalBurke
55
Они оба принимают функцию от необязательного типа к чему-то.
map()применяет функцию « как есть » к необязательному:
Примечание: - ниже показана иллюстрация функции map и flatmap, в противном случае Optional в первую очередь предназначен для использования только в качестве возвращаемого типа.
Как вы уже знаете, Optional - это вид контейнера, который может содержать или не содержать один объект, поэтому его можно использовать везде, где вы ожидаете нулевое значение (вы никогда не увидите NPE, если используете Optional должным образом). Например, если у вас есть метод, который ожидает объект person, который может быть обнуляемым, вы можете написать метод примерно так:
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));}classPerson{privateString phone;//setter, getters}
Здесь вы вернули тип String, который автоматически переносится в необязательный тип.
Если класс человека выглядел так, то есть телефон также необязательно
В этом случае вызывающая функция map обернет возвращаемое значение в Optional и выдаст что-то вроде:
Optional<Optional<String>>//And you may want Optional<String> instead, here comes flatMapvoid doSome(Optional<Person> person){Optional<String> phone = person.flatMap((p)->p.getPhone());
phone.ifPresent((ph)->dial(ph));}
PS; Никогда не вызывайте метод get (если вам нужно) для Optional, не проверяя его с помощью isPresent (), если вы не можете жить без исключений NullPointerException.
Я думаю, что этот пример может отвлечь от характера вашего ответа, потому что ваш класс Personзлоупотребляет Optional. Это противоречит намерению API использовать Optionalтаких членов - см. Mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/…
8bitjunkie
@ 8bitjunkie Спасибо за то, что указал на это, оно отличается от варианта Scala ..
SandeepGodara
6
Что мне помогло, так это взгляд на исходный код двух функций.
Карта - оборачивает результат в необязательный.
public<U>Optional<U> map(Function<?super T,?extends U> mapper){Objects.requireNonNull(mapper);if(!isPresent())return empty();else{returnOptional.ofNullable(mapper.apply(value));//<--- wraps in an optional}}
Что вы подразумеваете под flatMap«возвращает« необработанный »объект»? flatMapтакже возвращает сопоставленный объект, «обернутый» в Optional. Разница в том, что в случае flatMap, функция mapper оборачивает сопоставленный объект в то Optionalвремя как mapсам оборачивает объект Optional.
Дерек Махар
@DerekMahar удалил мой, нет необходимости повторно публиковать его, потому что вы правильно отредактировали свой комментарий.
maxxyme
3
Optional.map():
Принимает каждый элемент и, если значение существует, оно передается функции:
Добавленный теперь имеет одно из трех значений: trueили falseзаключенный в необязательный параметр , если optionalValueон присутствует, или пустой необязательный в противном случае.
Если вам не нужно обрабатывать результат, который вы можете просто использовать ifPresent(), у него нет возвращаемого значения:
optionalValue.ifPresent(results::add);
Optional.flatMap():
Работает аналогично тому же методу потоков. Выравнивает поток потоков. С той разницей, что если значение представлено, оно применяется к функции. В противном случае возвращается пустой необязательный параметр.
Вы можете использовать его для составления необязательных значений функций вызовов.
Предположим, у нас есть методы:
publicstaticOptional<Double> inverse(Double x){return x ==0?Optional.empty():Optional.of(1/ x);}publicstaticOptional<Double> squareRoot(Double x){return x <0?Optional.empty():Optional.of(Math.sqrt(x));}
Затем вы можете вычислить квадратный корень из обратного, например:
Optional<Double> result = inverse(-4.0).flatMap(MyMath::squareRoot);
или, если вы предпочитаете:
Optional<Double> result =Optional.of(-4.0).flatMap(MyMath::inverse).flatMap(MyMath::squareRoot);
Если какая- либо inverse()или squareRoot()возвращается Optional.empty(), то результат пуст.
Это не компилируется. Оба ваших выражения возвращают необязательный <Double>, а не Double, которому вы присваиваете результат.
JL_SO
@JL_SO ты прав. Потому что обратный Optional<Double>тип имеет тип возвращаемого значения.
nazar_art
3
Ладно. Вам нужно использовать «flatMap» только тогда, когда вы сталкиваетесь с вложенными опциями . Вот пример.
publicclassPerson{privateOptional<Car> optionalCar;publicOptional<Car> getOptionalCar(){return optionalCar;}}publicclassCar{privateOptional<Insurance> optionalInsurance;publicOptional<Insurance> getOptionalInsurance(){return optionalInsurance;}}publicclassInsurance{privateString name;publicString getName(){return name;}}publicclassTest{// map cannot deal with nested OptionalspublicOptional<String> getCarInsuranceName(Person person){return person.getOptionalCar().map(Car::getOptionalInsurance)// ① leads to a Optional<Optional<Insurance>.map(Insurance::getName);// ②}}
Как и Stream, Optional # map вернет значение, заключенное в Optional. Вот почему мы получаем вложенный Optional - Optional<Optional<Insurance>. И в ②, мы хотим отобразить это как страховой случай, вот как произошла трагедия. Корень вложенный необязательно. Если мы сможем получить значение ядра независимо от оболочек, мы это сделаем. Это то, что делает flatMap.
Stream#flatMap
иOptional#flatMap
.Ответы:
Используйте,
map
если функция возвращает нужный вам объект илиflatMap
если функция возвращаетOptional
. Например:Оба оператора печати печатают одно и то же.
источник
[flat]Map
когда-либо вызывать функцию отображения сinput == null
?Optional
Насколько я понимаю, сортировка, если она отсутствует, [JavaDoc] ( docs.oracle.com/javase/8/docs/api/java/util/… ), кажется, подтверждает это: « Если значение присутствует, примените .. . "Optional.of(null)
этоException
.Optional.ofNullable(null) == Optional.empty()
,Они оба принимают функцию от необязательного типа к чему-то.
map()
применяет функцию « как есть » к необязательному:Что произойдет, если ваша функция является функцией от
T -> Optional<U>
?Ваш результат теперь
Optional<Optional<U>>
!Вот что
flatMap()
значит: если ваша функция уже возвращает anOptional
,flatMap()
она немного умнее и не переносит ее дважды, возвращаяOptional<U>
.Это композиция из двух функциональных идиом:
map
иflatten
.источник
Примечание: - ниже показана иллюстрация функции map и flatmap, в противном случае Optional в первую очередь предназначен для использования только в качестве возвращаемого типа.
Как вы уже знаете, Optional - это вид контейнера, который может содержать или не содержать один объект, поэтому его можно использовать везде, где вы ожидаете нулевое значение (вы никогда не увидите NPE, если используете Optional должным образом). Например, если у вас есть метод, который ожидает объект person, который может быть обнуляемым, вы можете написать метод примерно так:
Здесь вы вернули тип String, который автоматически переносится в необязательный тип.
Если класс человека выглядел так, то есть телефон также необязательно
В этом случае вызывающая функция map обернет возвращаемое значение в Optional и выдаст что-то вроде:
PS; Никогда не вызывайте метод get (если вам нужно) для Optional, не проверяя его с помощью isPresent (), если вы не можете жить без исключений NullPointerException.
источник
Person
злоупотребляетOptional
. Это противоречит намерению API использоватьOptional
таких членов - см. Mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/…Что мне помогло, так это взгляд на исходный код двух функций.
Карта - оборачивает результат в необязательный.
flatMap - возвращает необработанный объект
источник
flatMap
«возвращает« необработанный »объект»?flatMap
также возвращает сопоставленный объект, «обернутый» вOptional
. Разница в том, что в случаеflatMap
, функция mapper оборачивает сопоставленный объект в тоOptional
время какmap
сам оборачивает объектOptional
.Optional.map()
:Принимает каждый элемент и, если значение существует, оно передается функции:
Добавленный теперь имеет одно из трех значений:
true
илиfalse
заключенный в необязательный параметр , еслиoptionalValue
он присутствует, или пустой необязательный в противном случае.Если вам не нужно обрабатывать результат, который вы можете просто использовать
ifPresent()
, у него нет возвращаемого значения:Optional.flatMap()
:Работает аналогично тому же методу потоков. Выравнивает поток потоков. С той разницей, что если значение представлено, оно применяется к функции. В противном случае возвращается пустой необязательный параметр.
Вы можете использовать его для составления необязательных значений функций вызовов.
Предположим, у нас есть методы:
Затем вы можете вычислить квадратный корень из обратного, например:
или, если вы предпочитаете:
Если какая- либо
inverse()
илиsquareRoot()
возвращаетсяOptional.empty()
, то результат пуст.источник
Optional<Double>
тип имеет тип возвращаемого значения.Ладно. Вам нужно использовать «flatMap» только тогда, когда вы сталкиваетесь с вложенными опциями . Вот пример.
Как и Stream, Optional # map вернет значение, заключенное в Optional. Вот почему мы получаем вложенный Optional -
Optional<Optional<Insurance>
. И в ②, мы хотим отобразить это как страховой случай, вот как произошла трагедия. Корень вложенный необязательно. Если мы сможем получить значение ядра независимо от оболочек, мы это сделаем. Это то, что делает flatMap.В конце концов, я настоятельно рекомендую вам Java 8 In Action , если вы хотите систематически изучать Java8.
источник