可选的map和orElse必须返回相同的类型

时间:2020-02-27 17:48:47

标签: java null optional

我有此代码:

Object s = ofNullable(resp).map(ResponseEntity::getBody).orElse(ex.getMessage());
ResponseEntity::getBody returns Object and ex.getMessage returns String

我收到一个编译器错误:

The method orElse(capture#10-of ?) in the type Optional<capture#10-of ?> is not applicable for the arguments (String)

但是我可以编写不带可选内容的代码,并且效果很好:

Object s = resp != null ? resp.getBody() : ex.getMessage();

1 个答案:

答案 0 :(得分:2)

问题源于Java如何进行类型推断。

方法引用(和lambda)是 polyexpressions 。这意味着相同的表达式可以具有不同的类型,具体取决于使用的位置。

因此,您的多表达式:

ofNullable(resp).map(obj1::get1)

具有 some 类型。

如果要在分配上下文中使用它:

Optional<Object> opt1 = ofNullable(resp).map(obj1::get1);
Optional<?> opt2      = ofNullable(resp).map(obj1::get1);

然后这两个都很好,因为类型推断约束允许可选的类型参数与变量的类型参数匹配。

但是,如果您使用表达式作为其他方法调用的接收者:

ofNullable(resp).map(obj1::get1).orElse(...)

然后Java首先推断ofNullable(...).map(...)的类型(它不再是多表达式),然后继续进行orElse

很显然,obj1.get1(resp)不会像您声明的那样返回Object,而是返回一些通配符类型。这是可选的Optional<some wildcard>的推断类型。那么orElse的参数也必须为some wildcard类型;唯一可能的值是null

有多种解决方法:

  • 您可以将ofNullable(...).map(...)的结果显式分配给类型为Optional<Object>的变量,然后在该变量上调用orElse

  • 您可以强制转换为Optional<Object>

    ((Optional<Object>) ofNullable(...).map(...)).orElse(...)
    
  • 您可以显式映射到Object:

    ofNullable(...).map(...).map(Object.class::cast)
    
  • 您可以改用lambda,然后将结果转换为Object

    ofNullable(...).map(r -> (Object) ...).orElse(...)
    

或者您可以保持简单,而不尝试使用Optional

Object s = (resp != null) ? obj1.get(resp) : ex.getMessage();