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

时间:2019-03-25 09:38:08

标签: java checked-exceptions

我想知道为什么Java编译器在方法永远不会抛出Exception时允许方法声明中的抛出。因为“引发”是一种处理异常的方法(告诉调用方对其进行处理)。

因为有两种处理异常的方法(引发和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
}

4 个答案:

答案 0 :(得分:25)

throws子句是方法合同的一部分。它要求方法的调用者的行为就像方法可能抛出指定的异常一样(即捕获异常或声明自己的throws子句)。

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

相反也可能。如果用于抛出throws子句中指定的异常的方法,但以后的版本不再抛出该异常,则应保留throws子句,以免破坏使用该子句的现有代码。您的方法。

第一个示例:

假设您有使用methodB的代码:

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

如果以后您想更改methodB以抛出IOException,则methodA将停止传递编译。

第二个示例:

假设您有使用methodB的代码:

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

    }
}

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

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

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

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

答案 1 :(得分:8)

因为签名定义了方法的约定。即使该方法现在不抛出IOException,也许将来也会发生,并且您想为此做准备。

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

答案 2 :(得分:0)

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

使用throw来提高可读性并指定异常的可能性,并使用try / catch告诉程序在发生异常的情况下该怎么做。

答案 3 :(得分:-1)

  1. 方法B引发IOException,因此调用方法B的方法负责捕获将由方法B引发的异常。尝试从其他方法调用methodB,它将要求您捕获它或重新抛出IOException。您将必须在某个地方捕获链中的IOException(在try / catch块中)。 因此您不会遇到编译时错误

    private void sampleMethod(){     尝试{         methodB();     } catch(IOException e){         // TODO自动生成的catch块         e.printStackTrace();     } }

  2. 在方法A中的
  3. try / catch无疑吞下了异常,这意味着methodA负责在try / catch块中捕获异常。 “ 任何Java程序中的每个语句都必须可访问,即每个语句必须至少可执行一次” 因此,由于try块没有任何导致IOException的代码,您将得到编译器错误。