English 中文(简体)
组件抛出的包装异常
原标题:
  • 时间:2008-10-16 06:41:45
  •  标签:

这是一种异常系统的风格,其中组件抛出特定于组件的异常。例如,所有数据访问类都会抛出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); 
}

你发现自己在做同样的事吗?你觉得它难看吗?

这个问题不是关于这种风格的有效性,而是在这种风格的限制内的事情。

问题回答

那真是太丑了。除了评价那个丑陋的风格之外,我认为没有太多可以评论的了。如果你已经拥有了处理不同问题的所有代码,使用原因肯定可以解决。只是使用

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

比起其他方式来说,它不太易于维护且更加混乱,而且我看不出使用它的任何好处。

鉴于您受限于使用它,我至少会尽量避免在 throws ComponentException 与 throws ComponentException + cause 两种情况下抛出异常,这会使事情变得比必要的更加混乱,在您的例子中,我会添加一个 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); 
}

"Cause()"是用于“异常链”,这些链只是因果相关,而不是语义相关的。

如果您需要它们区分不同的异常(例如,SQLExecutionException应该通过不同的操作进行更正,而不是AccessDeniedException),那么您的方法不适用(因为强制在每个catch中使用getCause()来查看需要做什么是可怕的,并且没有提供比直接在前面捕获正确的异常更好的好处)。

如果所有调用类只需要报告错误和取消,那么包装可能还可以,但我不会这样做,因为它增加的好处很少,如果您以后需要区分,将使您重写很多东西。

有用的是为相同类型的异常创建异常层次结构,例如: 创建异常层次结构

如果DataAccessException是根,则您可以例如有DataSourceUnavailableException,InvalidDataSourceException,InvalidDataException,然后您可以决定仅捕获父项(如果操作相同)或分别捕获每个异常。

顺便问一下,你为什么需要这样表现?

如果函数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();




相关问题
热门标签