Java 中涉及 throws 子句的类型推理解析过程

the*_*.18 6 java generics type-inference jls

考虑JLS \xc2\xa718.1.3 - 边界中的以下文章

\n

在这里,当我们尝试识别推理变量的边界集时,我们会遇到以下情况之一:

\n
\n

...

\n
    \n
  • throws \xce\xb1:推理变量 \xce\xb1 出现在 throws 子句中。
  • \n
\n

...

\n

throws \xce\xb1 形式的界限纯粹是信息性的:它指示解析优化 \xce\xb1 的实例化,以便在可能的情况下,它不是受检查的异常类型

\n
\n

我认为这个说法是不正确的:

\n
    \n
  • 这是因为理想情况下,提到 throws 子句是为了处理代码执行过程中可能发生的已检查异常。
  • \n
  • 那么为什么 JLS 仍然阻止\xce\xb1成为受检查的异常?
  • \n
  • 理想情况下,推理变量 \xce\xb1必须限制为Checked 类型的异常,而不是Unchecked 变体
  • \n
\n

我的理解正确还是我错过了什么?

\n

ern*_*t_k 4

我认为您对此声明的解释/理解有点误导:

\n
\n

throws \xce\xb1 形式的界限纯粹是提供信息的:它指示解析来优化 \xce\xb1 的实例化,以便在可能的情况下,它不是受检查的异常类型。

\n
\n

该行指的是分辨率,据我所知,它不是关于在哪里throws \xce\xb1,而是关于\xce\xb1推断出的位置,可以想象的是该方法的调用。

\n

考虑这个类:

\n
static class MyClass {\n\n    public static void main(String[] args) {\n        MyClass.<RuntimeException>something(0); // same as MyClass.something(1);\n\n        try {\n            MyClass.<IOException>something(2);\n        } catch (IOException ex) {\n            // checked exception\n        }\n    }\n\n    /**\n     * Will throw IOException if argument is 2, a RuntimeException otherwise\n     */\n    static <T extends Exception> void something(int a) throws T {\n        if (a == 2) {\n            throw (T) new IOException(); //of course it's a bad cast\n        } else {\n            throw (T) new Exception();\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

分析完两个something方法后,重点关注main方法中的调用:

\n

该调用MyClass.<IOException>something(0)需要一个 IOException。调用者知道这一点(假设完整记录的合同而不是紧密耦合的代码),并处理异常。\n
这已经告诉您该变量可以是受检查的异常,与您的想法相反。

\n

相反,MyClass.<RuntimeException>something(0)基于类似的理由,该调用预计会出现运行时异常。

\n

如何推断\xce\xb1T在上面的示例中)允许编译器跳过强制调用者捕获/处理异常(如果它要查看边界,否则它必须这样做)

\n

现在关于“优化”:有界的类型变量extends Exception可以合理地预期解析为已检查的异常。但是,如果调用者知道这将是一个运行时异常,它可以“通知”编译器它将是一个运行时异常。RuntimeException这就是我通过在类型见证中指定所做的(RuntimeException也是未明确给出类型参数时解析的类型)。

\n

我们可以花几天时间来解释“优化”,但至少我作为调用者不必尝试/捕获调用,而且我仍然没有扰乱编译器(第一次调用)。

\n