3

我正在玩一些异常程序,遇到了一些我以前从未遇到过的东西。

import java.io.*;

class ExceptionTest
{
  public static void main(String[] args)
  {
    try
    {
      System.out.println("hello");
    }
    catch(IOException ioe)
    {
      System.err.println("ioexception was thrown!!");
    }
  }
}

这会引发编译器错误:

ExceptionTest.java:10: exception java.io.IOException is never thrown in body of
corresponding try statement
catch(IOException ioe)
^
1 error

我的问题是为什么会这样?

为什么编译器会担心一段它肯定永远不会到达的代码。它可能只是一个警告,而不是一个完整的错误。毕竟,我们可能希望保留 catch 块作为我们将来可能进行的一些更改的备份,或者程序员可能只是在一些编辑后忘记将其删除。

我知道我知道它可以使我们免于不必要的击键等。但是它不应该过多地打扰编译器来引发错误。还是有其他原因??

代码中的 IOException catch 块也会产生编译器错误,但 Exception catch 块不会......为什么会这样?提前谢谢!!

4

4 回答 4

8

因为 Java 设计者认为系统应该以这种方式提供帮助。情况与此相同:

public class EarlyReturn {
    public void foo() {

        return;

        System.out.println("Hi");
    }
}

...这也会导致编译时错误。永远不会运行的代码是一件坏事,编译器通过让我们知道它永远不会运行来帮助我们,设计者认为它应该是错误而不是警告。

你可以改变你的代码来捕获Exception而不是IOException你喜欢,但是虽然这会让编译器让你这样做,但你仍然有永远不会运行的代码(这又是一件坏事)。

代码中的catch块也会IOException产生编译器错误,但Exceptioncatch块不会……这是为什么?

IOException是一个已检查的异常,并且只有已检查的异常才会以这种方式进行检查(这就是它们被称为的原因)。有已检查异常未检查异常RuntimeException及其子类)和错误Error及其子类)。从技术上讲,检查的异常是所有不是未经检查的异常或错误的异常(JLS 的第 11.1.1 节),但是——这有点暗角——并不是所有的检查的异常都经过检查。具体来说,检查异常会被检查,除非它们是Exception或它的类。从JLS 的第 11.2.3 节

如果catch子句可以捕获已检查的异常类,并且与该子句对应的块不能抛出作为 的子类或超类的已检查的异常类,除非是或 的超类,则这是编译时错误。E1trycatchE1E1ExceptionException

第 11 节的全部内容可能值得一读。正如您可以猜到的,这是 Java 的一部分,在早期发生了相当大的演变,导致对检查内容的定义有些复杂。

于 2012-05-15T03:09:08.880 回答
3

答案与更一般的问题相同:“为什么编译器将无法访问的代码视为错误?”。

  1. JLS 要求这样做 - 请参阅JLS 14.21。请注意,用于检测不可达代码的 JLS 规则专门涵盖了catch无法抛出异常的情况。
  2. 将无法访问的代码视为编译错误可以消除程序员所犯的一整类错误。这就是JLS 要求这样做的原因。

关于第二点,考虑一下:

try {
     System.out.println("Guards!! Someone is stealing the crown jewels!");
} catch(IOException ioe) {
     CallTheArmy();
}

写这篇文章的人可能会认为,如果我们不能提醒警卫(由于 IOException),那么军队就会被召唤。事实上,这不会发生,因为它println会默默地吃掉 IOException。

在这种情况下,您会很高兴编译器通过编译错误告诉您该问题。

于 2012-05-15T03:10:11.263 回答
2

Java 编译器不喜欢无法访问的代码。( JLS 14.21 ) 如果程序员忘记删除try ... catch块,那么这个错误将使他删除它。如果您将来进行可能引发的更改,IOException那么编译器会告诉您try ... catch再次包含该块。删除不必要的块当然不会损害代码,并且很可能更容易阅读。

编辑以反映已编辑的问题:“代码中的 IOException catch 块也会产生编译器错误,但 Exception catch 块不会......为什么会这样??提前谢谢!!”

异常捕获块更通用。它将捕获任何类型的异常(例如,包括RuntimeException s),因此如果 aRuntimeException被抛出,它是可访问的代码。

于 2012-05-15T03:13:33.310 回答
0

因为IOException不是RuntimeException,所以只有当里面的代码块try ... catch有任何声明 throws 的方法时才应该被捕获IOException

原因是:为了避免程序员的错误。:) 与以下情况相同:您在方法中返回一个值,并且在return语句之后,您有一行永远不会到达的代码,这种情况总是程序员的错误。

thagorn的详细解释:这是真的。RuntimeException 是“在 Java 虚拟机正常运行期间可以抛出的那些异常的超类”。(JavaDocs)。您的编译器知道没有办法用您的代码抛出 IOException,因为它不是 RuntimeException 并且没有明确地在任何地方抛出。

于 2012-05-15T03:06:21.577 回答