如果更高级别负责处理异常,则应在较低级别检查异常

时间:2013-08-15 20:46:22

标签: java exception exception-handling effective-java

这是来自Effective java的引用。

“在可能的情况下,处理较低层异常的最佳方法是通过确保较低级别的方法成功来避免它们。有时您可以通过在传递更高级别方法的参数之前检查更高级别方法的参数的有效性来实现此目的。在较低层。“

考虑一个名为“AccessControlContext actx”的对象,它从处理程序传播到较低级别。我们可以做一个更高级别的检查,“actx!= null”,但它是否需要再次在较低级别完成?

例如在psuedocode中:

class RestServlet {
   void verify Servlet(AccessControlContext actx) {
        // check made at higher level according to effective java
        if (actx == null) { throw exception; }  
        // do something
        Verify.checkAccessControl(actx); // calling lower leve
        // do something
    }
}

class Verify {
   static checkAccessControl(actx) {
        // DO I NEED NULL POINTER CHECK HERE AGAIN ?
   }
} 

虽然问题嵌套在评论中,但需要详细说明。 较低级别的冗余检查可确保防御性编码,但这是多余的。 它可能在javadocs中很好地说明它不接受null,但这并不能解决拥有无bug代码的目的。我们应该重复删除异常检查吗?

注意:这是一个随机的例子。我的问题并不是针对这个例子的。它是一个更广泛的问题,旨在了解复制例外的程度。

2 个答案:

答案 0 :(得分:1)

在验证参数时,我认为你不能经常这样做。我习惯于工作的方式,参数在代码的所有层中得到验证。如果方法无法处理空值(例如,它会导致nullpointer),则应该由方法本身来确保传递的参数不为null。对于错误的参数值会导致层中的异常进一步下降的方法也是如此。

我看到它的方式,如果一个错误的参数会导致异常,它是否是从高级别的参数验证或低级别的参数验证抛出的异常无关紧要,无论如何如果没有任何验证(或更糟糕的是,没有例外和错误的执行),它会比异常更好。

通过让每个方法负责验证其输入,即使它只是一个passthrough方法,也可以确保调用现有方法的任何新方法都不会传递错误参数,因为它会导致验证异常,无论被调用的方法是高级还是低级方法。

因此,在您的示例中,我将验证两种方法中的输入,并附带测试验证验证的行为应该如此。输入验证也可以像单行一样简单,查看验证类apache commons lang:http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/Validate.html

例如:

import org.apache.commons.lang.Validate;
import org.apache.commons.lang.StringUtils;

public class Something {
   public void doSomething(final Integer someInt, final String someString) {
       Validate.notNull(someInt, "Can't proceed when someInt is null!");
       Validate.isTrue(!StringUtils.isEmpty(someString, "Can't proceed when someString is null or empty!");
       //do stuff
   }
}

如果验证失败,将抛出将IllegalArgumentException定义为第二个参数的消息。然后测试可能如下所示:

public class SomethingTest {

    private Something something;

    @Rule
    public ExpectedException expectedException = ExpectedException.none();

    @Before
    public void setup() {        
        something = new Something();
    }

    @Test
    public void doSomethingShouldFailIfSomeIntIsNull() {
        expectedException.expect(IllegalArgumentException.class);
        expectedException.expectMessage("someInt is null");

        something.doSomething(null, "hello");
   }

   @Test
   public void doSomethingShouldFailIfSomeStringIsEmpty() {
        expectedException.expect(IllegalArgumentException.class);
        expectedException.expectMessage("someString is null or empty");

        something.doSomething(123, "");
   }

   //more tests..
}

答案 1 :(得分:0)

我不确定我对这种方法感到满意,如果从很多地方调用checkAccessControl怎么办?你必须依赖每个调用者进行空检查 - 这不是一种安全的方法。我将把null检查放到checkAccessControl方法中,如果检测到null,可能会抛出IllegalArgumentException。

所以,我的广泛方法是,如果你的方法依赖于呈现给它的特定值(例如参数不能为空),我会让它负责验证它。

你当然可以询问调用者为你验证参数(例如通过javadocs),但你不能强制执行它。