为什么抛出方法签名的一部分

Why is throws part of the method signature

为什么方法上的 throws 是其签名的一部分?包括它似乎很奇怪。这是一个阻碍的例子:

@Overide
public void foo() {
    throw new UnsupportedOperationException();
}

如果有人从外面看到这个方法,他们可能会在不知道它不受支持的情况下尝试使用它。他们只会在尝试 运行 代码时学习它。

但是,如果他们可以做这样的事情,他们会通过查看不支持的方法知道,如果 UnsupportedOperationException 没有扩展 RuntimeException,他们会得到一个编译错误。 EDIT1:但这是不可能的,因为 throws 是签名的一部分,因此覆盖将不起作用。

@Overide
public void foo() throws UnsupportedOperationException {
    throw new UnsupportedOperationException();
}

这个问题与 Java 的设计有关,所以我知道如果没有从事此工作的人中的一个人过来回答它可能很难回答,但我希望也许这个问题之前有人问过他们,或者可能有一个明显的理由以这种方式解释原因。

throws 部分并不表示该方法需要抛出上述异常,即使在特定情况下也不需要。它只告诉函数允许这样做。

包含 throws UnsupportedOperationException 并不意味着该方法不受支持。除了 UnsupportedOperationException 是一个 RuntimeException 所以一个方法可能 throw 无论如何。

现在由于在方法签名中需要它的原因,它归结为完全检查异常的能力。为了让编译器能够决定一个方法是否只能抛出指定的异常,它必须能够决定它调用的方法不能抛出未捕获的异常。

例如,这意味着重写一个方法意味着您不能添加可能抛出的异常,否则您将无法验证调用该方法的方法是否不能抛出它已经抛出的任何异常指定的。另一种方法是可能的(但我不确定 Java 是否支持该方法),用可能不会抛出的方法覆盖可能抛出的方法。

例如:

class B {
    int fubar(int) throws ExceptionA {
    }

    int frob(int) throws ExceptionA {
         return fubar(int);
    }
}

class D extends B {
    int fubar(int) throws ExceptionB {
    }
}
    

现在 frob 可能只指定 throw ExceptionA,但是在调用 this.fubar 时它会打开抛出其他东西的可能性,但是 fubar 可能仅定义为 throw ExceptionA。这就是 D.fubar 是无效覆盖的原因,因为这会打开 this.fubar 实际上抛出 ExceptionB 的可能性,并且编译器将无法保证 frob 不会t throw ExceptionB.

Java has two different types of exceptions: checked Exceptions and unchecked Exceptions.

未经检查的异常是 RuntimeException 的子类,您不必添加 throws 声明。所有其他异常都必须在方法主体中处理,可以使用 try/catch 语句或使用 throws 声明。

未经检查的异常示例:IllegalArgumentException 有时用于通知已使用非法参数调用方法。不需要投掷。

已检查异常的示例:IOException java.io 包中的某些方法可能会抛出。使用 try/catch 或将 throws IOException 添加到方法声明并将异常处理委托给方法调用者。

没有人提到的一件事是对您问题的非常重要的回答:

Why throws, on a method, is part of its signature?

throws 不是方法签名的一部分。

JLS 8.4.2. Method Signature 说得很清楚,即:

Two methods or constructors, M and N, have the same signature if they have the same name, the same type parameters (if any) (§8.4.4), and, after adapting the formal parameter types of N to the type parameters of M, the same formal parameter types.


If anyone were to see this method from the outside, they might try to use it without knowing that it is not supported.

这正是主要原因,为什么 throws 被设计为在编译时检查所有 检查异常 - 该方法的客户端将是知道这个方法可能会抛出什么。


已检查的异常 被强制处理或指定被抛出(但此规范不是方法签名的一部分)。

Unchecked Exceptions 不必处理或指定抛出,并且 Oracle's tutorial 擅长解释 - 为什么:

Runtime exceptions represent problems that are the result of a programming problem, and as such, the API client code cannot reasonably be expected to recover from them or to handle them in any way. Such problems include arithmetic exceptions, such as dividing by zero; pointer exceptions, such as trying to access an object through a null reference; and indexing exceptions, such as attempting to access an array element through an index that is too large or too small.