繁体   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