Java中处理多个异常

12

考虑以下Java代码:

try{

    // do something
    // this piece of code throws several checked exceptions.

} catch (IllegalArgumentException e) {
    handleException(e);
} catch (IllegalAccessException e) {
    handleException(e);
} catch (InvocationTargetException e) {
    handleException(e);
} catch (InstantiationException e) {
    handleException(e);
} catch (NoSuchMethodException e) {
    handleException(e);
} catch (IOException e) {
    handleException(e);
} catch (NoSuchFieldException e) {
    handleException(e);
}

我在try块中的代码引发了多个已检查异常。我想要做的就是在发生异常时记录一条消息(带有一些自定义的消息字符串)。也就是说,我对所有异常使用相同的异常处理逻辑。

我觉得上面的代码看起来不太好(代码行数更多,可读性降低)。

有没有更好的方法来处理这种情况?

以下解决方案不是最佳实践,因此不建议使用(由CheckStyle提供)。

try{
    // do something very bad
} catch (Exception e) {
    handleException(e);
} 

4
尽可能简洁地翻译如下: 在可以合并异常的情况下,请使用Java 7。捕获“Exception”本身并不是坏事,但将所有“Exception”实例都视为相等的处理则不妥。 - Maarten Bodewes
4
不应盲目遵循最佳实践。每个最佳实践都有反例。在这种情况下,如果您确定不会轻易更改异常处理,则可以使用单个通用catch。 - madth3
看看宏观的方法。通过良好的实践解决问题...如果你只捕获异常,你掩盖了未经检查的异常。这不是违反最佳实践的反例。 - Imaky
8个回答

16

在Java 6中,你没有比你已经建议的更吸引人的选项。

但是Java 7有一个multi-catch语句,你可以使用:

catch(IllegalArgumentException | IllegalAccessException | IOException exception) {
    handleException(e);
}

6

在你的情况下,我认为第二个选项就可以了。如果每种情况下的异常处理方式都相同,那么没有必要使你的代码过于复杂。


4
这样做,你掩盖了所有未经检查的异常。当你这样做时,上帝会哭泣。 - Imaky

3
在Java 7中,有一个新的并且非常出色的解决方案:你可以写成下面这样:
try{

    // do something
    // this piece of code throws several checked exceptions.

} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
    handleException(e);
} catch ...

在旧版本的Java中,捕获常见的子类——例如Exception——并不是一个坏主意。如果你经过考虑并选择了它作为最佳解决方案,那么这样做并没有问题,但是盲目地进行这样的操作则是不好的。


3

Java 6或更低版本的Java无法做任何事情。

使用Java 7,您可以像这样做:

catch(InstantiationException | IOException | NoSuchFieldException exception) {
        // handle our problems here.
}

在Java 6中,另一种“不好的做法”(但也许对你有用)是:

catch (Exception e) {
   if(! e instanceof RuntimeException) // Only non-checked exceptions!
       throw e;
   handleException(e) // All checked exception.
}

问题:您正在使用 instanceof。但是您的代码看起来更好...

3
这是另一个例子,说明受检异常是如何使Java程序员的生活变得痛苦。只要一段代码可能会抛出受检异常,那么这个代码片段很可能不是您想处理它们的地方。如果您的应用程序经过良好设计,则已经有了一个中央位置,即异常屏障,在该位置处理(记录)异常。如果是这样的情况,那么您应该将所有这些异常包装成RuntimeException并将它们传递到屏障。在这种情况下,以下是处理代码:
try {
  // do stuff
} catch (RuntimeException e) { 
  throw e; 
} catch (Exception e) { 
  throw new RuntimeException(e); 
}

1
你们对这个解决方案有什么想法?
try {
    // some code that might throw an exception.
} catch (Exception e) {
    if(e instanceof RuntimeException){
        throw (RuntimeException) e;
    }
    // log exception
}

优点:

  1. 代码量少,可以为所有已检查异常保持相同的异常处理逻辑。
  2. 不处理运行时异常和错误。捕获它们但将其抛回。

缺点:

  1. 不符合最佳实践检查,因为它仍然捕获异常。(尽管处理了捕获运行时异常的情况,但检查样式可能会失败。)
  2. RuntimeException进行向下转换可能会产生任何可能的副作用?

0

你的代码看起来像是你想要做这个:

try{
    // do something very bad
} catch (Throwable e) {
    handleException(e);
}

这不仅能捕获所有的异常,还能捕获错误——即在try/catch块内可能抛出的所有内容。

捕获所有异常并让所有错误通过通常不是正确的方法,但是捕获一长串任意选择的不相关异常更不可能是正确的做法。

您的异常列表看起来相当可疑。比如为什么要捕获IllegalArgumentException而不捕获NullPointerException或ClassCastException,这些异常在语义上处于类似的级别。而且您似乎在使用反射与IO结合,所以您还可能需要处理NoClassDefFoundError、ExceptionInInitializerError和其他错误。至于StackOverflowError甚至OutOfMemoryError呢?


我使用的异常只是为了举例说明情况。它们不是我从代码中寻找的“实际”异常。 - Veera

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接