在方法中没有 throws 声明的情况下抛出检查异常

Thrown checked exception without throws declaration in method

以下代码在 Java 13 上编译并 运行s:

public class CheckedExceptionSSCE {
    
    public static void main(String[] args) {
        try {
            methodNoThrowsDeclaration();
        } catch (Exception e) {
            // why is this throw allowed?
            // no throws in main()
            throw e;
        }
    }

    private static void methodNoThrowsDeclaration() {
        System.out.println("doesn't throw");
    }
}

为什么允许throw e

是在JLS的某处指定的吗?没找到,可能是我搜索的关键词不对。

编译器是否足够聪明,可以推断出不会抛出真正的已检查异常,从而允许代码编译并运行?

这是在 Java 7 中添加的功能。 如果您使用 catch 子句中的变量重新抛出异常,编译器可以导出异常类型。由于您没有要捕获的已检查异常,它知道 e 只能是 RuntimeException 并且不需要抛出定义。

更多信息: https://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html

方法:

private static void methodNoThrowsDeclaration() {
        System.out.println("doesn't throw");
    }

不抛出任何checked exception,由此SO thread可以读到:

You can throw unchecked exceptions without having to declare them if you really want to. Unchecked exceptions extend RuntimeException.

因此无需调整 main 方法签名。

从Java 语言规范(§14.18 throw 语句)可以读到:

ThrowStatement: throw Expression ;

At least one of the following three conditions must be true, or a compile-time error occurs:

  1. The type of the Expression is an unchecked exception class (§11.1.1) or the null type (§4.1).

  2. The throw statement is contained in the try block of a try statement (§14.20) and it is not the case that the try statement can throw an exception of the type of the Expression. (In this case we say the thrown value is caught by the try statement.)

  3. The throw statement is contained in a method or constructor declaration and the type of the Expression is assignable (§5.2) to at least one type listed in the throws clause (§8.4.6, §8.8.5) of the declaration.

您显示的代码至少遵循第一个条件。然而,让我们看下面的例子,其中上述三个条件中没有一个是 true,即如果你这样做:

private static void methodNoThrowsDeclaration() {
    System.out.println("doesn't throw");
    throw new Exception();
}

那会迫使你做:

private static void methodNoThrowsDeclaration() throws Exception {
    System.out.println("doesn't throw");
    throw new Exception();
}

这又会产生编译器错误:

Unhandled exception: java.lang.Exception

在语句 throw e;.