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

Why does the compiler allow throws when the method will never throw the Exception

我想知道为什么 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
}

throws 子句是方法契约的一部分。它要求方法的调用者表现得好像指定的异常可能会被方法抛出(即捕获异常或声明自己的 throws 子句)。

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

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

第一个例子:

假设您的代码使用 methodB:

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

如果以后想把methodB改成抛出IOExceptionmethodA会停止通过编译。

第二个例子:

假设您的代码使用 methodB:

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

    }
}

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

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

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

如果它是一个实例方法,还有另一个允许 throws 子句的原因,即使你不抛出异常 - 该方法可以被覆盖,覆盖方法可能会抛出异常,即使基础 class 实现没有。

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

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

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

使用 throws 提高可读性和指定异常的可能性,并使用 try/catch 告诉程序在发生异常时应该做什么。

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

    private void sampleMethod(){ 尝试 { 方法B(); } 赶上(IOException e){ // TODO 自动生成的 catch 块 e.printStackTrace(); } }

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