简体   繁体   English

Optional.flatMap 和 Optional.map 有什么区别?

[英]What is the difference between Optional.flatMap and Optional.map?

What's the difference between these two methods: Optional.flatMap() and Optional.map() ?这两种方法有什么区别: Optional.flatMap()Optional.map()

An example would be appreciated.一个例子将不胜感激。

Use map if the function returns the object you need or flatMap if the function returns an Optional .如果函数返回您需要的对象,则使用map ;如果函数返回Optional ,则使用flatMap For example:例如:

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.两个打印语句都打印相同的内容。

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> ?如果您的函数是来自T -> Optional<U>的函数,会发生什么?
Your result is now an Optional<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()的含义:如果您的函数已经返回OptionalflatMap()会更聪明一点,并且不会双重包装,返回Optional<U>

It's the composition of two functional idioms: map and flatten .它是两个功能性习语的组合: mapflatten

Okay.好的。 You only need to use 'flatMap' when you're facing nested Optionals .当您面对嵌套的 Optionals 时,您只需要使用 'flatMap' Here's the example.这是示例。

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.与 Stream 一样,Optional#map 将返回一个由 Optional 包裹的值。 That's why we get a nested Optional -- Optional<Optional<Insurance> .这就是为什么我们得到一个嵌套的 Optional -- Optional<Optional<Insurance> And at ②, we want to map it as an Insurance instance, that's how the tragedy happened.而在②处,我们想将其映射为一个Insurance实例,悲剧就是这样发生的。 The root is nested Optionals.根是嵌套的 Optionals。 If we can get the core value regardless the shells, we'll get it done.如果我们能够不顾外壳地获得核心价值,我们就会完成它。 That's what flatMap does.这就是 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 Action to you if you'd like to study Java8 Systematicly.最后,如果您想系统地学习 Java8,我强烈向您推荐Java 8 In Action

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).您可能已经知道 Optional 是一种容器,它可能包含也可能不包含单个对象,因此可以在您预期为空值的任何地方使用它(如果正确使用 Optional,您可能永远不会看到 NPE)。 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:例如,如果您有一个方法需要一个可以为空的 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.在这里,您返回了一个自动包装在 Optional 类型中的 String 类型。

If person class looked like this, ie phone is also 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.永远不要在不使用 isPresent() 检查的情况下在 Optional 上调用 get 方法(如果需要),除非你不能没有 NullPointerExceptions。

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
    }
}
  • 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 added has one of three values: true or false wrapped into an Optional , if optionalValue was present, or an empty Optional otherwise.现在添加了三个值之一: 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() ,则结果为空。

You can refer below link to understand in detail (best explanation which I could find):您可以参考以下链接以详细了解(我能找到的最佳解释):

https://www.programmergirl.com/java-8-map-flatmap-difference/ https://www.programmergirl.com/java-8-map-flatmap-difference/

Both map and flatMap - accept Function. map 和 flatMap - 都接受函数。 The return type of map() is a single value whereas flatMap is returning stream of values map() 的返回类型是单个值,而 flatMap 是返回值流

<R> Stream<R> map(Function<? super T, ? extends R> mapper)

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)

They do the same thing.他们做同样的事情。

The only difference is that, the lambda return's type is wrapped by Optional or not.唯一的区别是, lambda返回的类型是否由Optional包装

For normal usage, map is shorter than flatMap正常使用时, mapflatMap

Example:例子:

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

Output:输出:

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