【问题标题】:Java 8 - Difference between Optional.flatMap and Optional.mapJava 8 - Optional.flatMap 和 Optional.map 之间的区别
【发布时间】:2015-09-01 02:16:21
【问题描述】:

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

一个例子将不胜感激。

【问题讨论】:

  • @AlexisC。您的链接是关于 Stream 的地图和 flatMap,而不是可选的。
  • @Eran 没关系,如果您了解 map/flatMap 是如何工作的,无论它是否用于 Stream,对于 Optional 也是一样的。如果操作人员了解它对 Stream 的工作原理,那么他不应该问这个问题。概念是一样的。
  • @AlexisC。并不真地。 Optional 的 flatMap 与 Stream 的 flatMap 几乎没有共同之处。
  • @Eran 我说的是地图和平面地图之间的概念区别,我不是在Stream#flatMap 和@ 之间进行一对一的对应987654325@.

标签: java java-8 optional


【解决方案1】:

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

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

【讨论】:

  • 问题:[flat]Map 会用input == null 调用映射函数吗?我的理解是Optional 排序如果不存在 - [JavaDoc](docs.oracle.com/javase/8/docs/api/java/util/…) 似乎支持这一点 - “如果存在值,则应用 ...”。
  • @BoristheSpider Optional.of(null) != Optional.empty()
  • @DiegoMartinoia Optional.of(null) 是一个ExceptionOptional.ofNullable(null) == Optional.empty().
  • @BoristheSpider 是的,你是对的。我试图回答您的问题,但我认为我让它更加不清楚:从概念上讲, Optional.ofNullable(null) 不应该为空,但实际上它被认为是,因此 map/flatmap 不执行。跨度>
  • 我认为输入在 getOutputOpt 或 getOutput 中都不应该为空
【解决方案2】:

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

map() 将函数“按原样”应用于您拥有的选项:

if (optional.isEmpty()) return Optional.empty();
else return Optional.of(f(optional.get()));

如果您的函数是来自T -&gt; Optional&lt;U&gt; 的函数会怎样?
您的结果现在是Optional&lt;Optional&lt;U&gt;&gt;

这就是flatMap() 的意义所在:如果您的函数已经返回OptionalflatMap() 会更聪明一点,并且不会双重包装,而是返回Optional&lt;U&gt;

它是两个功能性习语的组合:mapflatten

【讨论】:

    【解决方案3】:

    好的。 只有在面对嵌套的 Optional 时才需要使用“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&lt;Optional&lt;Insurance&gt;。而在②处,我们想将其映射为一个Insurance实例,悲剧就是这样发生的。 根是嵌套的 Optionals。如果我们能够不顾外壳地获得核心价值,我们就会完成它。这就是 flatMap 所做的。

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

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

    【讨论】:

      【解决方案4】:

      注意:- 下面是 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
      }
      

      这里你返回了一个字符串类型,它自动包装在一个可选类型中。

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

      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() 检查的情况下调用 Optional 的 get 方法(如果需要),除非你不能没有 NullPointerExceptions。

      【讨论】:

      • 我认为这个例子可能会分散你的答案的本质,因为你的班级Person 滥用了Optional。对这样的成员使用 Optional 是违反 API 的意图 - 请参阅 mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/…
      • @8bitjunkie 感谢您指出这一点,它不同于 Scala 的 Option..
      【解决方案5】:

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

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

      【讨论】:

      • flatMap“返回'原始'对象”是什么意思? flatMap 还返回“包装”在 Optional 中的映射对象。区别在于flatMap 的情况下,映射器函数将映射对象包装在Optional 中,而map 本身将对象包装在Optional 中。
      • @DerekMahar 删除了我的,无需重新发布,因为您已正确编辑了您的评论。
      【解决方案6】:
      • Optional.map():

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

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

      现在 add 具有以下三个值之一:truefalse 包裹在 可选 中,如果存在 optionalValue , 或 empty 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(),则结果为空。

      【讨论】:

      • 这不会编译。您的两个表达式都返回 Optional 而不是您分配结果的 Double。
      • @JL_SO 你是对的。因为 inverse 有 Optional&lt;Double&gt; 类型作为返回类型。
      【解决方案7】:

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

      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)
      

      【讨论】:

      • 在您的方法签名中,两种返回类型都是流?我以为flatMap 会简单地解开嵌套的可选?你能解释一下这与流有什么关系吗?
      【解决方案8】:

      他们做相同的事情。

      唯一的区别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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-19
        • 2012-01-21
        • 2016-06-29
        相关资源
        最近更新 更多