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

时间:2015-06-16 10:09:56

标签: java java-8 optional

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

一个例子将不胜感激。

7 个答案:

答案 0 :(得分:116)

如果函数返回您需要的对象,则使用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);
}

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

答案 1 :(得分:46)

他们都从可选的类型中获取函数。

Optional<Optional<U>>在您拥有的可选项上应用“ 原样 ”功能:

flatMap()

如果您的功能是Optional的功能,会发生什么? 您的结果现在是flatMap()

这就是Optional<U>的含义:如果你的函数已经返回mapflatten有点聪明并且没有双重包裹它,那么返回var photos = []; var ImgUrl="images/Thomas.jpg"; photos[0] = new ContactField('url', ImgUrl,true); contact.photos = photos;

这是两个功能习语的组成:{{1}}和{{1}}。

答案 2 :(得分: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
}

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

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

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));
}

PS; 永远不要使用isPresent()调用get方法(如果需要)而不用isPresent()进行检查,除非你不能在没有NullPointerExceptions的情况下生活。

答案 3 :(得分:5)

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

地图 - 将结果包装在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
    }
}

答案 4 :(得分:3)

  • Optional.map()

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

Optional<T> optionalValue = ...;
Optional<Boolean> added = optionalValue.map(results::add);

现在已添加具有以下三个值之一:truefalse包装在 可选 中,如果{ {1}}存在,否则为 空可选

如果您不需要处理结果,则只需使用optionalValue,它就没有返回值:

ifPresent()
  • optionalValue.ifPresent(results::add);

工作原理类似于相同的流方法。展平流。不同之处在于,如果显示值,则将其应用于功能。否则,将返回一个空的可选内容。

您可以使用它来构成可选的值函数调用。

假设我们有方法:

Optional.flatMap()

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

  

Double result = inverse(-4.0).flatMap(MyMath :: squareRoot);

或者,如果您愿意:

  

双重结果=可选.of(-4.0).flatMap(MyMath :: inverse).flatMap(MyMath :: squareRoot);

如果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)); } inverse()返回squareRoot(),则结果为空。

答案 5 :(得分:3)

好的。面对嵌套的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>。在②,我们希望将其映射为保险实例,这就是悲剧的发生方式。 根是嵌套的Optionals。如果我们能获得核心价值而不管外壳如何,那么我们就完成它。这就是flatMap的功能。

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

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

答案 6 :(得分:0)

您可以参考以下链接详细了解(我能找到的最佳解释):

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)