Java 如果上级处理异常,是否应在下级检查异常

Java 如果上级处理异常,是否应在下级检查异常,java,exception,exception-handling,effective-java,Java,Exception,Exception Handling,Effective Java,这是来自有效java的引用 在可能的情况下,处理较低层异常的最佳方法是通过确保较低层方法成功来避免这些异常。有时,您可以通过在将较高层方法的参数传递到较低层之前检查其有效性来做到这一点 考虑一个名为“AccessControlContext actx”的对象,该对象从处理程序分发到较低级别。我们可以执行更高级别的检查“actx!=null”,但是否需要再次在较低级别执行该检查 例如,在psuedocode中: class RestServlet { void verify Servlet(

这是来自有效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代码的目的。我们应该重复异常检查吗


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

我不确定我是否会对这种方法感到满意,如果从许多地方调用了
checkAccessControl
,会怎么样?您必须依靠每个调用方执行空检查-这不是一种安全的继续方式。我将把null签入
checkAccessControl
方法,如果检测到null,可能会抛出IllegalArgumentException

因此,我的广义方法是,如果您的方法依赖于提供给它的特定值(例如参数不能为null),我会让方法负责验证它


当然,您仍然可以要求调用者为您验证参数(例如通过javadocs),但您不能强制执行。

在验证参数方面,我认为您不能太频繁。按照我习惯的工作方式,参数在代码的所有层中都经过验证。如果一个方法不能处理null值(例如,它将导致null指针),那么应该由该方法本身来确保传递的参数不是null。对于参数值不正确会导致层中更深层的异常的方法也是如此

在我看来,如果一个坏参数会导致异常,不管它是从高级别的参数验证引发的异常还是从低级别的参数验证引发的异常,它无论如何都比根本没有验证时它会导致的异常要好(甚至更糟糕的是,没有例外和错误的执行。)

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

因此,在您的示例中,我将验证这两种方法中的输入,并附带测试以验证验证的行为是否正确。输入验证也可以像一行程序一样简单,请查看apache commons lang的验证类:

例如:

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..
}

如果直接调用low-levl方法呢?