最好在进程之前进行验证,还是只抛出异常?

时间:2011-05-16 10:55:04

标签: language-agnostic error-handling

考虑以下代码:

x = Repo.GetX(13);
Services.Process(x);

我可以在处理它之前检查x是否为null,或者如果X为null并使用try / catch块,我可以让Services.Process()抛出异常。

哪种方法更可取?

(或者我应该同时做两件事,只是在特殊情况下x从检索到处理它的某种程度上变为空?)

4 个答案:

答案 0 :(得分:1)

像往常一样,这类问题的正确答案是:它取决于。

如果可能,最好的方法是定义执行此类检查的边界。边界内的所有东西都可以依赖于所有被初始化的东西。如果仍然是一个NULL偷偷摸摸,用NPE炸毁是非常合适的。

通常在尝试执行实际工作之前检查前提条件可以使代码更清晰。

如果你不能在你的系统中建立这些边界,那么问题是:当x为NULL并且未处理结果异常时会发生什么,当你不处理它时你有什么选择?

在许多情况下,无论如何你都无法做很多事情,然后让异常上升到ui(或服务接口或其他)的调用堆栈就好了。

但有时使用null参数调用进程会破坏硬件,杀死病人或者其他方面真的很讨厌。在这种情况下:在潜在的有害行为之前检查。

答案 1 :(得分:1)

如果你想在以下两者之间作出决定:

x = Repo.GetX(13);
try {
    Services.Process(x);
} catch (NullPointerException) {
    System.err.println('x is NULL');
}

x = Repo.GetX(13);
if (x != NULL) {
    Services.Process(x);
} else {
    System.err.println('x is NULL');
}

然后要注意他们并不意味着同样的事情。第一个捕获由Process抛出的任何 NullPointerException。第二个只处理x本身为NULL的情况 - 如果Process执行x.foo().bar()x.foo()返回NULL,则不处理。

您应根据可以处理的错误来决定两者之间的关系。

Services.Process被记录为抛出NullPointerException的情况下,当且仅当x为NULL时,所以(假设我们相信文档)两者的意思相同,那么我就是做第二个。这样,如果文档是谎言,并且Services.Process中有一个错误导致它抛出其他情况,那么我们就不会错误地处理/报告异常,就好像x实际上是NULL一样它不是。

因此,在两种情况下捕获并抑制异常:

  1. 你知道什么(有点东西)导致了这个错误,而且你知道你可以处理这种情况并且无论如何都会继续。
  2. 从程序或环境中的意外故障中保护一些相当外部的代码,如事件循环。理想情况下,这会导致大量日志记录,因为系统未能按预期执行(可能是由于缺少资源或未满足的依赖项),或者某个人的代码中存在错误。
  3. 不要因为你知道可能导致异常的一个情况而抓住,并且当出于其他原因可能抛出相同的异常时可以处理。我想你可以做到:

    x = Repo.GetX(13);
    try {
        Services.Process(x);
    } catch (NullPointerException) {
        if (x == NULL) {
            System.err.println('x is NULL');
        } else {
            throw;
        }
    }
    

    但在这种情况下,我觉得这种情况毫无疑问:因为我们可以提前检查x是否为空,我们也可以。但是,有些情况下你会遇到异常,因为事先预测它是否会发生是不可能的或者是愚蠢的:

    String s = Rep.GetString(13);
    try {
        f = Float.parseFloat(s);
        System.out.println('is a number');
    } catch (NumberFormatException) {
        System.out.println('not a number');
    }
    

    我们可以在调用s之前检查parseFloat是否是有效数字,但这基本上会做同样的工作两次 - 检查一个字符串是一个有效的浮点数是与实际转换它几乎一样。所以抓住这个例外是有意义的 - 我们知道这意味着什么,我们知道如何应对它,我们无法真实地阻止它发生。

    (或者你可以使用DecimalFormat.parse,它根本不会抛出)

答案 2 :(得分:0)

更好的检查。异常处理通常很昂贵。

答案 3 :(得分:0)

应该使用异常处理来处理异常。

如果你的东西 x 永远不应该为null,请使用try / catch语句。如果 x 在某些情况下将为null use和if。