使用Optional
,我想根据映射结果返回接口的某个实现(First
或Second)
。这是First
和{ {1}}实现:
Second
以下public interface MyInterface {
Number number();
}
用法是错误的:
Optional
不能将orElse
final String string = ... // might be null final Number number = Optional.ofNullable(string) .map(string -> new First()) .orElse(new Second()) // erroneous line .number();
应用于(com.mycompany.First)
为什么由于类(com.mycompany.Second)
和First
都实现了接口Second
而方法MyInterface
返回MyInterface::number
,所以行是错误的?如何正确实现呢?
答案 0 :(得分:5)
我发现方法Optional::map
返回U
,这不允许将返回的First
应用到另一种类型的Second
。显式转换为其接口或在map
方法中要求它是一种方法:
final Number number = Optional.ofNullable("")
.<MyInterface>map(string -> new First())
.orElse(new Second())
.number();
__
编辑:发布问题后,我发现了这一点。但是,由于我在其他任何地方都找不到类似的解决方案,因此我将两者都保留。
答案 1 :(得分:5)
问题在于Java 推断映射类型为First
,而Second
不是First
的实例。您需要明确地向Java轻推一下才能知道正确的类型:
private static void main(String... args)
{
final String string = "";
final Number number = Optional.ofNullable(string)
.<MyInterface>map(str -> new First()) // Explicit type specified
.orElse(new Second())
.number();
}
这是沿方法链进行类型推断的一般限制。不限于Optional
。
有人建议在方法链中进行类型推断。看到以下问题:Generic type inference not working with method chaining?
也许在Java的未来版本中,编译器将足够聪明以解决此问题。谁知道。
答案 2 :(得分:2)
我会这样写,而无需显式强制转换:
Optional.ofNullable(string)
.map(s -> {
MyInterface m = new First();
return m;
})
.orElse(new Second())
.number();
答案 3 :(得分:1)
您也可以写:
Optional.ofNullable(string)
.map(s -> new First())
.filter(MyInterface.class::isInstance)
.map(MyInterface.class::map)
.orElse(new Second())
.number()
或者,将实用程序功能添加到您的代码库中:
// the Class Object is unused and only present so the Compiler knows which Type you actually want
public static <T, R> Function<? super T, R> mapAs(Function<? super T, ? extends R> mappingFunction, Class<R> clazz) {
return mappingFunction::apply;
}
Optional.ofNullable(string)
.map(mapAs(s -> new First(), MyInterface.class))
.orElse(new Second())
.number()
答案 4 :(得分:0)
在其他答案中,解释也是如此,其类型是在使用map
时会误认为正在使用的orElse
的类型,因此,代表建议解决方案的更简洁的方法是:
Optional.ofNullable(string)
.map(s -> (MyInterface) new First()) // casting rather than binding here
.orElse(new Second())
.number();