[英]What is the difference between Optional.flatMap and Optional.map?
這兩種方法有什么區別: Optional.flatMap()
和Optional.map()
?
一個例子將不勝感激。
如果函數返回您需要的對象,則使用map
;如果函數返回Optional
,則使用flatMap
。 例如:
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);
}
兩個打印語句都打印相同的內容。
它們都從可選項的類型中獲取功能。
map()
將函數“按原樣”應用於您擁有的選項:
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
。
好的。 當您面對嵌套的 Optionals 時,您只需要使用 'flatMap' 。 這是示例。
public class Person {
private Optional<Car> optionalCar;
public Optional<Car> getOptionalCar() {
return optionalCar;
}
}
public class Car {
private Optional<Insurance> optionalInsurance;
public Optional<Insurance> getOptionalInsurance() {
return optionalInsurance;
}
}
public class Insurance {
private String name;
public String getName() {
return name;
}
}
public class Test {
// map cannot deal with nested Optionals
public Optional<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>
。 而在②處,我們想將其映射為一個Insurance實例,悲劇就是這樣發生的。 根是嵌套的 Optionals。 如果我們能夠不顧外殼地獲得核心價值,我們就會完成它。 這就是 flatMap 所做的。
public Optional<String> getCarInsuranceName(Person person) {
return person.getOptionalCar()
.flatMap(Car::getOptionalInsurance)
.map(Insurance::getName);
}
最后,如果您想系統地學習 Java8,我強烈向您推薦Java 8 In Action 。
注意:- 下面是 map 和 flatmap 函數的說明,否則 Optional 主要設計為僅用作返回類型。
您可能已經知道 Optional 是一種容器,它可能包含也可能不包含單個對象,因此可以在您預期為空值的任何地方使用它(如果正確使用 Optional,您可能永遠不會看到 NPE)。 例如,如果您有一個方法需要一個可以為空的 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));
}
class Person{
private String phone;
//setter, getters
}
在這里,您返回了一個自動包裝在 Optional 類型中的 String 類型。
如果人員類看起來像這樣,即電話也是可選的
class Person{
private Optional<String> phone;
//setter,getter
}
在這種情況下,調用 map 函數會將返回的值包裝在 Optional 中並產生如下內容:
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));
}
附言; 永遠不要在不使用 isPresent() 檢查的情況下在 Optional 上調用 get 方法(如果需要),除非你不能沒有 NullPointerExceptions。
幫助我的是查看這兩個函數的源代碼。
Map - 將結果包裝在 Optional 中。
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 - 返回“原始”對象
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
}
}
Optional.map()
:獲取每個元素,如果值存在,則將其傳遞給函數:
Optional<T> optionalValue = ...;
Optional<Boolean> added = optionalValue.map(results::add);
現在添加了三個值之一: true
或false
包裝到Optional ,如果optionalValue
存在,否則為空 Optional 。
如果您不需要處理結果,您可以簡單地使用ifPresent()
,它沒有返回值:
optionalValue.ifPresent(results::add);
Optional.flatMap()
:工作原理與流的相同方法類似。 使流變平。 不同之處在於,如果顯示該值,則將其應用於功能。 否則,返回一個空的可選項。
您可以使用它來編寫可選的值函數調用。
假設我們有方法:
public static Optional<Double> inverse(Double x) {
return x == 0 ? Optional.empty() : Optional.of(1 / x);
}
public static Optional<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()
,則結果為空。
您可以參考以下鏈接以詳細了解(我能找到的最佳解釋):
https://www.programmergirl.com/java-8-map-flatmap-difference/
map 和 flatMap - 都接受函數。 map() 的返回類型是單個值,而 flatMap 是返回值流
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
他們做同樣的事情。
唯一的區別是, lambda
返回的類型是否由Optional
包裝。
正常使用時, map
比flatMap
短
例子:
package bj;
import java.util.Optional;
import static java.lang.System.out;
public class App {
public static void main(String[] args) {
out.println(Optional.of(10).map (x -> x * x));
out.println(Optional.of(10).flatMap(x -> Optional.of(x * x)));
out.println(Optional.of(10).map (x -> Optional.of(x * x).get()));
out.println(Optional.<Integer>empty().map (x -> x * x));
out.println(Optional.<Integer>empty().flatMap(x -> Optional.of(x * x)));
out.println(Optional.<Integer>empty().map (x -> Optional.of(x * x).get()));
}
}
輸出:
Optional[100]
Optional[100]
Optional[100]
Optional.empty
Optional.empty
Optional.empty
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.