我已经编程三年了。当我编写程序时,我习惯处理所有已知的异常并以友好的方式向用户发出警告。最近我看到了一些代码,几乎所有的方法都被包含在try/catch块中。作者说这是防御性编程的一部分。我想知道,这真的是防御性编程吗?你推荐将所有代码放在try块中吗?
我已经编程三年了。当我编写程序时,我习惯处理所有已知的异常并以友好的方式向用户发出警告。最近我看到了一些代码,几乎所有的方法都被包含在try/catch块中。作者说这是防御性编程的一部分。我想知道,这真的是防御性编程吗?你推荐将所有代码放在try块中吗?
我的基本规则是:除非你能够解决导致异常的问题,否则不要捕获它,让它上升到可以处理它的级别。
根据我的经验,95% 的 catch 块要么忽略异常(catch {}
),要么仅记录错误并重新抛出异常。后者可能看起来是正确的做法,但在实践中,当每个级别都这样做时,你最终只会得到五份相同错误消息的日志。通常这些应用程序在最高层有一个“忽略 catch”(因为“我们在所有较低层都有 try/catch”),导致应用程序非常缓慢,错过了很多异常,并且错误日志太长,没有人愿意去查看它。
过度使用Try...Catch不是防御性编程,而是将尸体竖立起来。
在面对意外异常时,Try…Finally可以广泛用于恢复。只有当你预计到一个异常并知道如何处理它时,才应该使用Try..Catch。
有时我看到Try..Catch System.Exception的情况,其中catch块仅记录异常并重新抛出。这种方法至少存在以下三个问题:
不,这不是“防御性编程”。你的同事试图用一个好习惯的流行词来为他的坏习惯辩解。
他所做的应该被称为“掩盖问题”。这就像从方法调用中一致地忽略错误状态返回值。
“防御性编程”的概念是指以一种方式编写代码,使其能够从错误情况中恢复或避免错误情况的发生。例如:
private String name;
public void setName(String name) {
}
当name == null时,您如何处理?抛出异常还是接受它?如果没有名称就没有对象是没有意义的,那么应该抛出异常。那么当name == ""时呢?
但是...后来您编写了一个编辑器。在设置UI时,您发现有些情况下用户可以决定将名称去掉,或者在用户编辑时名称可能变为空。
另一个例子:
public boolean isXXX (String s) {
}
在这里,防御策略通常是在 s == null 时返回 false(尽可能避免 NPE)。
或者:
public String getName() {
}
为了避免在调用代码中出现NPE,一个防御性程序员可能会在name==null时返回""。
随机捕获异常是不好的。那么该怎么办呢?
捕获您可以实际处理有意义的异常是好的。这些情况很容易识别和维护。
作为一个辅助翻译,我想说一下,每当我的同事在方法签名中使用“throws Exception”而不是列出方法真正抛出的异常类型时,我都想去开枪打他们的头。问题在于,经过一段时间后,你会发现有14个级别的调用都说“throws Exception”,因此重构以使它们声明它们真正抛出的异常是一个很大的练习。