19

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

因为有两种处理异常的方法(抛出和尝试/捕获)。在 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
}
4

4 回答 4

27

throws条款是方法合同的一部分。它要求方法的调用者表现得好像该方法可以抛出指定的异常(即捕获异常或声明它们自己的throws子句)。

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

反之亦然。如果用于抛出throws子句中指定的异常的方法,但它的未来版本不再抛出它,您应该保留该throws子句,以免破坏使用您的方法的现有代码。

第一个例子:

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

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

如果稍后你想更改methodB为 throw IOExceptionmethodA将停止传递编译。

第二个例子:

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

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

    }
}

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

这个例子在 is 时不是很有趣methodAprivate因为它只能在本地使用(在同一个类中,很容易修改所有调用它的方法)。

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

如果它是一个实例方法,那么即使您不抛出异常,也有另一个原因允许该throws子句 - 该方法可以被覆盖,即使基类实现没有,覆盖方法也可能抛出异常。

于 2019-03-25T09:43:36.510 回答
8

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

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

于 2019-03-25T09:43:44.013 回答
0

关键字 throws 告诉程序员该方法中可能发生 IOException。现在,如果您没有指定 try/catch,则意味着当抛出异常时程序将停止工作,而在 try/catch 中,如果抛出异常,您将通过执行其他操作来处理它。

使用 throws 来提高可读性并指定异常的可能性,并使用 try/catch 告诉程序在出现异常时要做什么。

于 2019-03-25T09:50:09.840 回答
-1
  1. methodB抛出IOException,所以调用methodB的方法负责捕获methodB将抛出的异常。尝试从其他方法调用 methodB,它会要求您捕获它或重新抛出 IOException。您必须在某个地方捕获链中的 IOException(在 try/catch 块中)。所以你不会得到编译时错误

    私人无效样本方法(){尝试{方法B();} catch (IOException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } }

  2. methodA 中的 try/catch 诚然吞下了异常,这意味着 methodA 负责在 try/catch 块中捕获异常。“任何java程序中的每条语句都必须是可访问的,即每条语句必须至少可执行一次”所以,你会得到编译器错误,因为你的try块没有任何代码会导致IOException。

于 2019-03-25T10:49:50.407 回答