簡體   English   中英

Optional.flatMap 和 Optional.map 有什么區別?

[英]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()的含義:如果您的函數已經返回OptionalflatMap()會更聰明一點,並且不會雙重包裝,返回Optional<U>

它是兩個功能性習語的組合: mapflatten

好的。 當您面對嵌套的 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);

現在添加了三個值之一: truefalse包裝到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包裝

正常使用時, mapflatMap

例子:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM