Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么在这种情况下允许抛出选中的异常类型?_Java_Exception_Language Lawyer_Throw_Checked Exceptions - Fatal编程技术网

Java 为什么在这种情况下允许抛出选中的异常类型?

Java 为什么在这种情况下允许抛出选中的异常类型?,java,exception,language-lawyer,throw,checked-exceptions,Java,Exception,Language Lawyer,Throw,Checked Exceptions,我无意中注意到这个throw语句(从一些更复杂的代码中提取)编译: void foo() { try { } catch (Throwable t) { throw t; } } 有那么一个短暂但快乐的时刻,我以为我最终决定就这样死去了,但在这一点上,我仍然感到骄傲: void foo() { try { } catch (Throwable t) { Throwable t1 = t; throw t

我无意中注意到这个
throw
语句(从一些更复杂的代码中提取)编译:

void foo() {
    try {

    } catch (Throwable t) {
        throw t;
    }
}
有那么一个短暂但快乐的时刻,我以为我最终决定就这样死去了,但在这一点上,我仍然感到骄傲:

void foo() {
    try {

    } catch (Throwable t) {
        Throwable t1 = t;
        throw t1;
    }
}

try
块不必为空;似乎只要代码不抛出已检查的异常,它就可以拥有代码。这似乎是合理的,但我的问题是,语言规范中的什么规则描述了这种行为?就我所见,显式禁止它,因为
t
表达式的类型是一个已检查的异常,它没有被捕获或声明为抛出。(?)。下面是一个适用于Java 7但不适用于Java 6的示例:

public static demoRethrow() throws IOException {
    try {
        throw new IOException("Error");
    }
    catch(Exception exception) {
        /*
         * Do some handling and then rethrow.
         */
        throw exception;
    }
}

您可以阅读整篇文章来解释这些更改。

JLS中详细描述了此行为,具体内容如下:

一种
throw
语句,其抛出的表达式是最终的或有效的
catch
子句C的最后一个异常参数可以引发异常 E类敌我识别码:

  • E是一个异常类,
    try
    语句的
    try
    块 声明C可以抛出
    ;及

  • E的赋值是否与C的任何可捕获异常兼容 班级;及

  • E与任何可捕获的异常都不兼容 在同一
    try中,在C的左边声明的
    catch
    子句的类 声明

(我的重点。)


您的第二个示例失败,因为
t1
不是“catch
子句的异常参数”。

我认为您提到的JLS-文本中的措辞是一个错误,应该用Java SE 7更新,而不是

描述预期行为的JLS文本位位于:

如果
throw
语句的抛出表达式是
catch
子句C的最终或有效的最终异常参数,则该语句可以抛出异常类E iff:

  • E是声明C的
    try
    语句的
    try
    块可以抛出的异常类;及
  • E的赋值与C的任何可捕获异常类兼容;及
  • E的赋值与同一
    try
    语句中C左边声明的
    catch
    子句的任何可捕获异常类都不兼容
第一个要点是相关的;因为
catch
-子句参数
t
实际上是final(意味着它从未被赋值、递增或递减;请参见),
throw t
只能抛出
try
块可以抛出的东西

但是正如您所说的,§14.18中的编译时检查并没有考虑到这一点。§11.2.2不决定什么是允许的,什么是不允许的;相反,它应该是对各种限制的后果的分析。(该分析确实反馈到了规范的更规范的部分——§14.18本身在其第二个要点中使用了它——但§14.18不能仅仅说“如果它抛出了一个根据§11.2.2它不能抛出的异常,那就是编译时错误”,因为这是循环的。)

因此,我认为需要调整§14.18,以适应§11.2.2的意图


好发现

看起来是这样,但在langspec中它在哪里?14.18说“以下三个条件中至少有一个必须为真,否则会发生编译时错误”。这不是三个条件之一,确切地说。由于Java 7中引入的增强分析,可以确定第三个条件(throw语句包含在方法或构造函数声明中,并且表达式的类型可分配(§5.2)给声明的throws子句(§8.4.6,§8.8.5)中列出的至少一个类型。)是真的。但是表达式类型是
Throwable
,不能“分配”给
RuntimeException
Error
,因为这需要强制转换,看起来是§5.5,而不是§5.2。@Boann这是真的。但是,编译器现在可以检测到该
可丢弃
必须是
运行时异常
错误
,因为
可丢弃
的其他子类型不能在
try
块中抛出。如果throwable可能是一个checked异常(因为这样的异常可能会在
try
-块中抛出),那么它会抱怨抛出的正是这个checked异常(正如您在问题中已经提到的)。+1。这实际上提出了关于多批次的相同问题,
catch(最终运行时异常|错误e){throw e;}
,因为根据§14.20,
e
的类型是
Throwable
。§14.18还说“尽管
throw
语句可以抛出的异常类型在§11.2.2中指定”。这句话前面的要点有点措词不当。@ntoskrnl确实有点措词不当。我完全错过了11.2.2。与较旧的JLS相比,中的“三个条件”基本上没有变化,但发生了巨大的变化。有趣。但这肯定是正确的部分,因为如果我插入
t=null之前<代码>抛出t,因此它不再是“有效的最终”,它现在抱怨未声明的异常。(接受你的答案,顺便说一句,因为它是最详细的。谢谢。)@ntoskrnl:对——但这并不能取代条件列表。(请注意,§11.2.2中的“可以扔”表示“可能扔”,而不是“允许扔”。)第三个条件不是“有点糟糕”