提问人:Sy Pham 提问时间:10/1/2023 更新时间:10/2/2023 访问量:77
原始和参数化之间的区别 调用 orElseGet(Supplier) 时可选
Difference between raw and parameterized Optional when invoking orElseGet(Supplier)
问:
请考虑以下代码:
public class Main {
public static void main(String[] args)
// throws Exception // line 1
{
Optional empty1 = Optional.empty(); // line 2
Optional<Object> empty2 = Optional.empty(); // line 3
Optional.empty().orElseThrow(() -> new Exception("Empty optional")); // line 4
empty1.orElseThrow(() -> new Exception("Empty optional")); // line 5
empty2.orElseThrow(() -> new Exception("Empty optional")); // line 6
}
}
当第 1 行被注释时,第 4、5、6 行都会报告编译时错误:
- 第 4 行和第 6 行:未处理的异常:java.lang.Exception
- 第 5 行:未处理的异常:java.lang.Throwable 这让我觉得第 4 行是用类型参数调用的,就像第 6 行一样,但是什么让抛出的确切异常存在差异?
<Object>
当第 1 行取消注释时,只有第 5 行报告编译时错误:未处理的异常:java.lang.Throwable。如果我将第 1 行更改为投掷投掷,它将得到解决。为什么抛出 Exception 不足以让第 5 行解决编译时错误?
答:
区别是由于在 Java 中使用了原始类型。orElseThrow 的方法签名为:
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
因此,对于第 2 行和第 5 行的情况,您有:
Optional empty1 = Optional.empty(); // line 2
empty1.orElseThrow(() -> new Exception("Empty optional")); // line 5
在上面的签名情况下,编译器没有提供类型,即使认为它有,它也会生成原始调用。它将用其上限替换 X,即 Throwable,而 T 将是 Object。结果是:orElseThrow
T
X
public Object orElseThrow(Supplier exceptionSupplier) throws Throwable
^^^^^^^^^
因此,编译器报告:
error: unreported exception Throwable
案例:
Optional.empty().orElseThrow(() -> new Exception("Empty optional")); // line 4
更有趣的是,这里没有指定显式类型,但编译器报告被抛出的错误。所以它与前一种情况不同。您必须再次查看所用函数的签名,在本例中为 Optional.empty():Exception
public static<T> Optional<T> empty()
^^^ ~~~ type inference
重要的部分是表明它将从封闭上下文推断其类型。在编译器中无法推断类型,而是使用类型。我相信 JLS 是这样说的:<T>
T
line 4
Object
https://docs.oracle.com/javase/specs/jls/se10/html/jls-18.html#jls-18.1.3
如果 Pl 没有 TypeBound,则绑定的 αl <: Object 将显示在集合中。
在 Oracle 教程中:
https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html
编译器需要类型参数 T 的值,因此它启动 值为 Object。因此,调用 Collections.emptyList 返回 List<Object 类型的值>
重要的是,您不是像第 2 行和第 5 行那样处理原始类型,而是处理泛型类型(泛型类型是 ),因此当调用 orElseThrow 时,它的签名是line 4
T
Object
public Object orElseThrow(Supplier exceptionSupplier) throws Exception
两种泛型类型 NAD 都是已知的,因此会生成泛型函数调用,这最终会导致您的示例中出现以下编译器错误:T
X
error: 未上报异常 Exception;
现在,第 3 行和第 6 行显式使用泛型类型 Object,这使得 orElseThrow 的签名如前所述:
public Object orElseThrow(Supplier exceptionSupplier) throws Exception
这给出了相同的错误:
error: 未上报异常 Exception;
评论