从组件中包装异常

时间:2008-10-16 06:41:45

标签: java exception

存在这种异常系统样式,其中组件抛出特定于组件的异常。例如,所有数据访问类都抛出DataAccessException

在这种风格中,我经常发现自己必须捕获并重新抛出组件特定的异常,因为被调用的方法被定义为throws Exception

try {
    int foo = foo();
    if (foo != expectedValue) {
        throw new ComponentException("bad result from foo(): " + foo);
    }
    bar();
}
catch (ComponentException e) { 
    throw e; 
}
catch (Exception e) { 
    throw new ComponentException(e); 
}

你发现自己也这样做了吗?你觉得它难看吗?

这个问题不是关于这种风格的有效性,而是在这种风格的约束下。

2 个答案:

答案 0 :(得分:3)

这很难看。我想,没有更多的评论这种丑陋的风格了。如果您已经拥有使用原因处理不同问题的所有代码,那就可以了。只是使用

try {
  componentCall();
} catch (ComponentException e) {
  Throwable t = e.getCause();
  //Handle each possible cause
}

比其他方式更难以维护和混淆,重点是我认为使用它没有任何好处。

鉴于您只能使用它,我至少会尝试避免在有和没有原因的情况下抛出ComponentException,这会使它更加困惑,在您的示例中我添加了InvalidFooException并将其添加为通用ComponentException的原因。

try {
    int foo = foo();
    if (foo != expectedValue) {
        throw new InvalidFooException("bad result from foo(): " + foo);
    }
    bar();
}
catch (Exception e) { 
    throw new ComponentException(e); 
}

getCause()仅供chains of exceptions用于因果关系而非语义相关。

如果您需要它们来区分不同的异常(例如,SQLExecutionException应该通过与AccessDeniedException不同的操作来纠正)那么您的方法不适用(因为强制在每个catch中使用getCause()来查看需要做的很糟糕,并没有提供任何好处,只能在前面捕获正确的异常。)

如果所有调用类都必须报告错误并取消,那么包装可能没问题,但是我不会这样做,因为它增加了很少的好处,如果你以后需要区分将使你重写的东西。

有用的是为同一类型的例外创建一个hierarchy of exceptions,排在:

如果DataAccessException是根,那么你可以例如有DataSourceUnavailableException,InvalidDataSourceException,InvalidDataException然后你可以决定只捕获任一个父项(如果操作是相同的)或单独捕获每个异常。

顺便说一下,为什么你需要这样做呢?

答案 1 :(得分:0)

这样做可能不那么难看(如果函数foo()是声明抛出异常的函数):

int foo;
try {
    foo = foo();
}
catch (Exception e) { 
    throw new ComponentException(e); 
}
if (foo != expectedValue) {
    throw new ComponentException("bad result from foo(): " + foo);
}
bar();