Java 8 - Optional.flatmap和Optional.map之间的区别

cod*_*ent 136 java optional java-8

这两种方法有什么区别:Optional.flatMap()Optional.map()

一个例子将不胜感激.

ass*_*ias 133

使用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);
}
Run Code Online (Sandbox Code Playgroud)

两个打印语句都打印相同的内容.

  • @DiegoMartinoia`Uption.of(null)`是一个`异常`.`Optional.ofNullable(null)== Optional.empty()`. (11认同)
  • 问题:`[flat] Map`会用`input == null`调用映射函数吗?我的理解是`可选`排序,如果它不存在 - [JavaDoc](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#flatMap-java.util.function功能 - 似乎支持这一点 - "_如果存在值,则应用...... _". (3认同)
  • 我认为 getOutputOpt 或 getOutput 中的输入永远不应该为空 (2认同)

Die*_*oia 51

它们都从可选类型中获取函数.

map()在您拥有的可选项上应用" 原样 " 功能:

if (optional.isEmpty()) return Optional.empty();
else return Optional.of(f(optional.get()));
Run Code Online (Sandbox Code Playgroud)

如果你的函数是函数,会发生什么T -> Optional<U>
你的结果现在是Optional<Optional<U>>!

flatMap()是关于:如果你的函数已经返回一个Optional,flatMap()有点聪明并且没有双重包装它,返回Optional<U>.

它是两个功能成语的组成:mapflatten.


San*_*ara 6

注意: - 下面是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
}
Run Code Online (Sandbox Code Playgroud)

在这里,您返回了一个String类型,该类型自动包装在Optional类型中.

如果人类看起来像这样,即电话也是可选的

class Person{
  private Optional<String> phone;
  //setter,getter
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,调用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));
}
Run Code Online (Sandbox Code Playgroud)

PS; 永远不要使用isPresent()调用get方法(如果需要)而不用isPresent()进行检查,除非你不能没有NullPointerExceptions.


Rob*_*roj 6

帮助我的是看两个函数的源代码.

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
    }
}
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • “flatMap”“返回‘原始’对象”是什么意思?`flatMap` 还返回“包装”在 `Optional` 中的映射对象。不同之处在于,在“flatMap”的情况下,映射器函数将映射对象包装在“Optional”中,而“map”本身将对象包装在“Optional”中。 (2认同)

naz*_*art 5

  • Optional.map():

获取每个元素,如果值存在,则将其传递给函数:

Optional<T> optionalValue = ...;
Optional<Boolean> added = optionalValue.map(results::add);
Run Code Online (Sandbox Code Playgroud)

现在添加具有三个值之一:true或者false包装到一个Optional(如果optionalValue存在),或者一个空的Optional,否则。

如果你不需要处理结果,你可以简单地使用ifPresent(),它没有返回值:

optionalValue.ifPresent(results::add); 
Run Code Online (Sandbox Code Playgroud)
  • 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));
}
Run Code Online (Sandbox Code Playgroud)

然后您可以计算倒数的平方根,例如:

Optional<Double> result = inverse(-4.0).flatMap(MyMath::squareRoot);
Run Code Online (Sandbox Code Playgroud)

或者,如果您愿意:

Optional<Double> result = Optional.of(-4.0)
                     .flatMap(MyMath::inverse)
                     .flatMap(MyMath::squareRoot);
Run Code Online (Sandbox Code Playgroud)

如果 theinverse()或 thesquareRoot()返回Optional.empty(),则结果为空。


小智 5

好的。当您面对嵌套的 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);       // ?
    }

}
Run Code Online (Sandbox Code Playgroud)

与 Stream 一样,Optional#map 将返回一个由 Optional 包装的值。这就是为什么我们得到一个嵌套的 Optional -- Optional<Optional<Insurance>。在 ? 处,我们想将其映射为 Insurance 实例,这就是悲剧发生的方式。根是嵌套的 Optionals。如果我们能得到核心价值而不考虑shell,我们就完成了。这就是 flatMap 所做的。

public Optional<String> getCarInsuranceName(Person person) {
    return person.getOptionalCar()
                 .flatMap(Car::getOptionalInsurance)
                 .map(Insurance::getName);
}
Run Code Online (Sandbox Code Playgroud)

最后,如果你想系统地学习 Java8 ,我强烈向你推荐Java 8 In Action