6

我一直在阅读有关未检查与检查问题的信息,没有任何在线资源真正清楚地说明差异以及何时使用两者。

据我了解,它们都在运行时被抛出,它们都表示超出逻辑预期范围的程序状态,但是必须显式捕获已检查的异常,而未检查的异常则不能。

我的问题是,假设为了论证,我有一个方法可以将两个数字相除

double divide(double numerator, double denominator)
{    return numerator / denominator;    }

以及需要在某处进行划分的方法

void foo()
{    double a = divide(b, c);    }

谁负责检查分母为零的情况,应该检查还是不检查异常(忽略 Java 内置的除法检查)?

那么,divide 方法是按原样声明还是按原样声明

double divide(double numerator, double denominator) throws DivideByZeroException
{
    if(denominator == 0) throw DivideByZeroException
    else ...
}

void foo()
{
    try{
        double a = divide(b, c);
    }
    catch(DivideByZeroException e)
    {}
}

或没有检查异常,如下所示:

double divide(double numerator, double denominator)
{
    if(denominator == 0) throw DivideByZeroException
    else ...
}

void foo()
{
    if(c != 0)
       double a = divide(b, c);
}

并允许 foo 进行除以零检查?

这个问题最初出现在我编写的一个数学程序中,其中用户输入数字,逻辑类执行计算。我从来不确定 GUI 是否应该立即检查不正确的值,或者内部逻辑是否应该在计算期间捕获它们并抛出异常。

4

6 回答 6

7

确实很有趣的话题!

在阅读并尝试了很多方法来处理一般错误和异常之后,我学会了区分程序员错误预期错误

程序员的错误永远不应该被捕获,而应该尽早和艰难地崩溃(!)。程序员错误是由于逻辑错误,应该修复根本原因。

应始终捕获预期的错误。此外,当捕获到预期的错误时,必须向用户显示一条消息。这有一个重要的含义——如果预期的错误不应该显示错误,最好检查方法是否会抛出而不是让它抛出。

因此,应用于您的示例,我会想“这对用户来说应该如何?”

  1. 如果应该显示错误消息(在浏览器输出、控制台、消息框中),我会抛出异常并在尽可能靠近 UI的地方捕获它并输出错误消息。
  2. 如果不应该显示错误消息,我会检查输入而不是抛出。

在旁注中:我从不抛出DivideByZeroException也不NullPointerException- 我让 JVM 为我抛出这些。在这种情况下,您可以制作自己的异常类或使用合适的内置检查异常。

于 2011-02-21T20:53:06.580 回答
1

我最喜欢的关于 Java 中已检查和未检查异常之间哲学差异的讨论:

http://www.javapractices.com/topic/TopicAction.do?Id=129

于 2011-02-21T20:35:52.213 回答
1

Java 异常仅由编译器检查,但是 Java 设计者决定将它们分成多个类别,主要涉及扩展的超类

  • java.lang.Exception- 称为检查异常
  • java.lang.RuntimeException称为未经检查的异常 - 作为奖励 java.land.RuntimeException 扩展 java.lang.Exception (以简化catch块中的处理,而不仅仅是)
  • java.lang.Error- 错误,也是未经检查的,很少需要由用户空间代码处理,但了解它们及其差异是一个主要优点。它们包括(最著名的):链接错误、stackoverflow、内存不足、断言错误
  • java.lang.Throwable-检查!和所有异常的母亲,很少需要直接子类化它,但有些出于未知原因

因此,需要声明异常并处理正确的传播(仅在编译级别上),未经检查的异常会自动传播,除非需要,否则开发人员不应提供处理。

通常预计会发生已检查的,并且需要在已经蓬松的 java 代码中额外冗长。

最糟糕的做法包括:catch (Throwable t){}出于多种原因,除非必要,否则通常不应处理错误,并且大多数错误通常会导致线程死亡。

于 2011-02-21T20:44:34.323 回答
1

假设由于数学运算而引发检查异常。例如除法(根据您的帖子)。
这意味着每个整数除法都应该出现在 try 块中!
实际上除法可以抛出一个 ArithmeticException 这是未经检查的异常,因此无需捕获它。
实际上你不应该抓住它,因为它是一种发生的异常情况,通常只能通过代码更正来解决。
在您的情况下,您的代码应该在实际除以零之前做一些事情。
如果您已达到允许实际除以零的步骤,那么您无能为力。该程序是错误的,最好是修复而不是试图通过抛出/捕获异常来伪装它

于 2011-02-21T21:02:08.817 回答
0

简短的回答,因为一些优点和缺点已经被命名:这是个人或组织风格的问题。没有一个在功能上比另一个更好。您(或您的项目)将不得不自行决定是使用受检异常还是未受检异常,或两者兼而有之。

Oracle 的 Java 教程建议您对应用程序可以恢复的所有错误使用检查异常,对应用程序无法恢复的错误使用未检查异常。但根据我的经验,大多数应用程序可能会从大多数(可能不是在启动期间)异常中恢复。失败的操作将被中止,但应用程序保持活动状态。

我宁愿只使用受检异常或未受检异常。混合可能会导致混淆和不一致的使用。务实。做对你的情况有意义的事情。

于 2011-02-21T21:02:36.333 回答
0

永远不要明确地抛出RuntimeExceptions。如果您认为需要,那么只需让运行时执行此操作,而不是使用throw.

于 2011-02-22T02:29:22.833 回答