为什么编译器允许抛射,而方法永远不会抛出异常

2022-09-02 12:25:42

我想知道为什么java编译器允许在方法声明中抛出,而方法永远不会抛出异常。因为“throws”是处理异常的一种方式(告诉调用方处理它)。

由于有两种处理异常的方法(throws和try/catch)。在 try/catch 中,它不允许捕获未在 try 块中引发的异常,但它允许在可能不会引发异常的方法中引发。

private static void methodA() {
    try {
        // Do something
        // No IO operation here
    } catch (IOException ex) {  //This line does not compile because
                              //exception is never thrown from try
        // Handle   
    }
}

private static void methodB() throws IOException { //Why does this //compile when excetion is never thrown in function body
    //Do Something 
    //No IO operation
}

答案 1

该条款是该方法合同的一部分。它要求方法的调用方表现得好像指定的异常可能由该方法引发(即捕获异常或声明自己的子句)。throwsthrows

方法的初始版本可能不会引发子句中指定的异常,但将来的版本可以在不破坏API的情况下引发它(即调用该方法的任何现有代码仍将通过编译)。throws

反之亦然。如果用于引发子句中指定的异常的方法,但其将来的版本不再引发该异常,则应保留该子句,以免破坏使用方法的现有代码。throwsthrows

第一个示例:

假设您有此代码,它使用:methodB

private static void methodA() {
    methodB(); // doesn't have throws IOException clause yet
}

如果以后要改成 throw ,将停止传递编译。methodBIOExceptionmethodA

第二个例子:

假设您有此代码,它使用:methodB

private static void methodA() {
    try {
        methodB(); // throws IOException
    }
    catch (IOException ex) {

    }
}

如果从 的未来版本中删除该子句,将不再通过编译。throwsmethodBmethodA

当 is 时,此示例不是很有趣,因为它只能在本地使用(在同一类中,可以轻松地修改调用它的所有方法)。methodAprivate

但是,如果它变成 ,则您不知道谁使用(或将使用)您的方法,因此您无法控制由于添加或删除子句而可能中断的所有代码。publicthrows

如果它是一个实例方法,那么即使您不引发异常,也允许该子句的另一个原因 - 该方法可以被重写,并且重写方法可能会引发异常,即使基类实现没有。throws


答案 2

因为签名定义了方法的协定。即使该方法现在没有抛出IOException,也许将来会抛出IOException,并且您希望为这种可能性做好准备。

假设您现在只是为该方法提供了一个虚拟实现,但是您知道,稍后,实际的实现可能会引发 IOException。如果编译器阻止您添加此 throws 子句,则在提供该方法的实际实现后,您将被迫(递归地)对该方法的所有调用进行返工。


推荐