10

我已经阅读了有关此的所有内容,但我仍然不明白如何使用已检查和未检查的异常。我想我仍然无法理解这个概念。我在 StackOverflow 上阅读过,最好使用未检查的异常而不是检查的异常,但是 Eclipse强制我使用检查的异常,如FileNotFoundException(AFAIK,如果 Eclipse 强制我插入一个 try/catch 块,它是一个检查的异常)。我想知道,有什么办法可以将检查翻译成未检查?到底在处理什么?我不明白处理异常是什么。

我在这里有这个例子,我真的很想知道如何处理(?)这个。这是一个检查异常,对吧?

public void readFile() {
    File foo = new File("./foo.bar");
    try {
        BufferedReader bufferedReader = new BufferedReader(new FileReader(foo));
    } catch (FileNotFoundException e) {
        // What should I do here?
    }
    getDataFromFile(bufferedReader);
}

我见过人们在这里做的各种事情。有些打印堆栈跟踪,这是我通常做的,我看不出它有什么问题。它为我提供了调试所需的信息。有些人忽略它们,我认为不应该这样做(我看到 JNode OS 引导程序忽略了一个异常)。有些人只是throws在签名中添加声明。有些会在那个东西里面抛出更多异常!(我想也许这就是使用未检查而不是检查的意思?)

此外,如果您添加throws声明,您将被迫进一步放置一个 try/catch 块,如果您有一个非常大的应用程序,这很不方便。对不起,我只是一无所知。完全地。我正在努力学习优秀而优雅的设计,这对我来说是一种折磨。

4

4 回答 4

6

未经检查的异常

是一个例外,因为某些事情本来就不应该发生,因此无法预料。它处理仅当您的程序有错误时才会出现的情况。

它是 的子类RuntimeException(它是 的子类Exception),通常使用IllegalArgumentExceptionNullPointerExceptionIllegalStateException

未经检查的运行时异常表示通常反映程序逻辑中的错误并且在运行时无法合理恢复的情况。


检查异常

是可能发生的事情,由于系统其余部分的不可预见的情况。它不在您的直接控制范围内,但不一定是错误,而是可能遇到的情况。

它是 的子类Exception

来自:例外


在你的例子中,

文件不存在是您需要处理的情况,因为它可能发生,即使在生产代码中,如果某些条件盛行(磁盘已满)。这使它成为一个检查异常。


处理异常:

例外旨在提供更好的用户体验。所以你应该向用户报告错误,如果你不能继续,优雅地终止。

  1. 如果确实是您预料到的情况,那么您可能应该将问题告知用户,并在必要时优雅地终止,或者继续做下一件事。

  2. 如果它是未经检查的异常,您可以做的最好的事情就是告诉用户发生了意外错误,因为这不是一开始就应该发生的事情,然后将堆栈跟踪报告给您。

于 2012-11-11T17:13:17.340 回答
1

让我们以您的示例(修改)本身来解释。

public void readFile() {
    BufferedReader bufferedReader = null;
    try {
            File foo = new File("./foo.bar");
        bufferedReader = new BufferedReader(new FileReader(foo));
    } catch (FileNotFoundException e) {
        // What should I do here?
    }
    getDataFromFile(bufferedReader);
}

当您遇到FileNotFoundException异常时,您的 bufferedReader 不会使用文件流初始化。在这种情况下,您的下一条语句 iegetDataFromFile(bufferedReader);将失败,因为没有 bufferedReader 来读取数据。

因此,在catch块中,您可以执行以下两项操作:

  1. 抛出一个新的自定义异常并从程序中返回
  2. 尝试更正再次获取文件句柄的问题(一个示例可能是在这种情况下使用默认文件),因此bufferedReader正确初始化。

这样,CheckedException在编写程序本身的情况下很有帮助。它们为您提供有关可能故障的输入,并使您能够预先做出适当的处理决定。

另一方面,未经检查的异常(例如NullPointerException在编译时难以识别)可能会被忽视。如果发生但未处理,它们会在运行时引起问题。

于 2012-11-11T17:47:36.297 回答
1

已检查的异常是一件令人头疼的事情。

很抱歉使用这种生硬的语言,但它们是 Java 最严重的设计错误之一!如果你必须处理仍然使用已检查异常的遗留 API,例如 Eclipse 或 Java 自己的 API,我个人所做的就是将它们包装到我自己的未检查异常中。使用您自己的标记类是一种很好的做法。这有助于您将这些异常识别为由您的代码引起的,例如在日志文件中或在调试时。

就我个人而言,我对调用我的标记类感到非常满意,BullshitFree因此我可以重新抛出检查的异常,如下所示

try {
    // call to legacy API that still uses checked exceptions
} catch(CheckedException exception) {
    throw new BullshitFree(exception);
}

确保您的BullshitFree异常类实际上是扩展RuntimeException的,因此它是未选中的!

在您的代码示例中,有两个选项。如果有办法从中恢复,例如通过创建文件或将错误报告给用户,请这样做。如果没有,或者它只是您自己使用的一个小脚本,请将其包装在一个BullshitFree异常中,然后用剩下的时间学习 Ruby 或其他精心设计的语言……</p>

您的里程可能会有所不同。

于 2012-11-23T09:36:58.870 回答
1

首先,例外是​​你的朋友:) - 不,真的。异常是一种非常强大且安全的错误处理方式。

基本上,Java 中已检查和未检查异常的区别在于对异常的预期反应:

已检查异常通常用于将某种操作的“意外”结果传达给调用者,调用者被认为想要显式处理该异常状态。

未经检查的异常通常是被认为或多或少无法恢复的异常。它用于指示假定使整个操作无效的某些故障情况。就像NullPointerException这些异常在几乎所有操作中都或多或少是潜在的。让它们检查意味着调用者需要在错误处理中完成一些令人讨厌的开销。

在您的示例中,您可能会这样:

public void readFile() {
    File foo = new File("./foo.bar");
    try {
        BufferedReader bufferedReader = new BufferedReader(new FileReader(foo));
        getDataFromFile(bufferedReader);  // If the file could not be found above, this will never execute!
    } catch (IOException e) {
        // React, e.g.:
        System.out.println("Data could not be read due to an IO error.");
    }

}

重新抛出异常或将一个异常包装到另一个异常中并不少见。- 例如,当发生IOException罢工时,您可能希望在将异常按原样或修改给调用者之前进行一些清理,关闭一些打开的文件等,以便他可以以适当的方式处理异常。

您如何实际处理特定异常几乎完全取决于您。根据运行代码的用户(例如您自己)和环境,打印堆栈跟踪可能没问题。或者,也许,您想在暂停后重试刚刚执行的操作。或者,在给出的示例中,您可以向用户显示一条消息并要求他重新输入文件名等。

后者是可以有效使用不同类别异常的方式:A FileNotFoundException(它是 的子类IOException)可以通过用户交互来恢复;裸机IOException可能被认为是不可恢复的,因为在最坏的情况下,它甚至可能表示某种硬件故障。

于 2012-11-11T17:28:43.617 回答