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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30864583/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 10:17:24  来源:igfitidea点击:

Java 8 - Difference between Optional.flatMap and Optional.map

javajava-8optional

提问by codependent

What's the difference between these two methods: Optional.flatMap()and Optional.map()?

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

An example would be appreciated.

一个例子将不胜感激。

采纳答案by assylias

Use mapif the function returns the object you need or flatMapif the function returns an Optional. For example:

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

Both print statements print the same thing.

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

回答by Diego Martinoia

They both take a function from the type of the optional to something.

它们都从可选类型到某物的类型中获取一个函数。

map()applies the function "as is" on the optional you have:

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

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

What happens if your function is a function from T -> Optional<U>?
Your result is now an Optional<Optional<U>>!

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

That's what flatMap()is about: if your function already returns an Optional, flatMap()is a bit smarter and doesn't double wrap it, returning Optional<U>.

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

It's the composition of two functional idioms: mapand flatten.

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

回答by SandeepGodara

Note:- below is the illustration of map and flatmap function, otherwise Optional is primarily designed to be used as a return type only.

注意:- 下面是 map 和 flatmap 函数的说明,否则 Optional 主要设计为仅用作返回类型。

As you already may know Optional is a kind of container which may or may not contain a single object, so it can be used wherever you anticipate a null value(You may never see NPE if use Optional properly). For example if you have a method which expects a person object which may be nullable you may want to write the method something like this:

您可能已经知道 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
}

Here you have returned a String type which is automatically wrapped in an Optional type.

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

If person class looked like this, i.e. phone is also Optional

如果 person 类看起来像这样,即电话也是 Optional

class Person{
  private Optional<String> phone;
  //setter,getter
}

In this case invoking map function will wrap the returned value in Optional and yield something like:

在这种情况下,调用 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; Never call get method (if you need to) on an Optional without checking it with isPresent() unless you can't live without NullPointerExceptions.

PS; 永远不要在 Optional 上调用 get 方法(如果你需要)而不用 isPresent() 检查它,除非你不能没有 NullPointerExceptions。

回答by Robert Niestroj

What helped me was a look at the source code of the two functions.

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

Map- wraps the result in an Optional.

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- returns the 'raw' object

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

回答by nazar_art

  • Optional.map():
  • Optional.map()

Takes every element and if the value exists, it is passed to the function:

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

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

Now addedhas one of three values: trueor falsewrapped into an Optional, if optionalValuewas present, or an empty Optionalotherwise.

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

If you don't need to process the result you can simply use ifPresent(), it doesn't have return value:

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

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

Works similar to the same method of streams. Flattens out the stream of streams. With the difference that if the value is presented it is applied to function. Otherwise, an empty optional is returned.

工作原理类似于流的相同方法。展平流的流。不同之处在于,如果提供了该值,则它会应用于函数。否则,返回一个空的可选项。

You can use it for composing optional value functions calls.

您可以使用它来组合可选的值函数调用。

Suppose we have methods:

假设我们有方法:

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

Then you can compute the square root of the inverse, like:

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

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

or, if you prefer:

或者,如果您愿意:

Optional<Double> result = Optional.of(-4.0).flatMap(MyMath::inverse).flatMap(MyMath::squareRoot);

If either the inverse()or the squareRoot()returns Optional.empty(), the result is empty.

如果inverse()squareRoot()返回Optional.empty(),则结果为空。

回答by momonannan

Okay. You only need to use 'flatMap' when you're facing nested Optionals. Here's the example.

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

}

Like Stream, Optional#map will return a value wrapped by a Optional. That's why we get a nested Optional -- Optional<Optional<Insurance>. And at ②, we want to map it as an Insurance instance, that's how the tragedy happened. The root is nested Optionals. If we can get the core value regardless the shells, we'll get it done. That's what flatMap does.

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

In the end, I stronly recommed the Java 8 In Actionto you if you'd like to study Java8 Systematicly.

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