捕获throwable并处理特定异常

时间:2015-07-23 10:52:57

标签: java exception exception-handling

好的,我知道抓住throwable不是一个好主意:

    try {
         // Some code
    } catch(Throwable e) { // Not cool!
        // handle the exception
    }

但是最近我正在阅读一个开源代码,我看到了这段有趣的代码(至少对我而言):

    try {
        // Some Code
    } catch (Throwable ex){
        response = handleException(ex, resource);
    }

    private handleException(Throwable t, String resource) {
        if (t instanceof SQLEXception) {
               // Some code
        } else if (t instanceof IllegalArgumentException) {
               //some code
        } //so on and so forth
    }

这似乎不是那么糟糕?这种方法有什么问题?

9 个答案:

答案 0 :(得分:19)

你有多种原因不应该抓住Throwable。首先,Throwable包括Error s - 如果其中一个出现,应用程序通常不会做多少。此外,Throwable减少了发现的可能性,发生了什么。你得到的只是"发生了一些不好的事情" - 这可能是一场灾难,也可能只是一种滋扰。

另一个方法更好但当然我仍然不会抓住Throwable,但是如果可能的话,尽量抓住更具体的异常。否则你会抓住所有东西,然后尝试找出发生了哪种坏事。你的例子可以写成......

try {
    ...
} catch (SQLEXception ex){
    response = ... ;
} catch (IllegalArgumentException ex){
    response = ...;
}

...这会减少if ( ... instanceof ... )块的数量(只需要因为作者首先决定在一个大桶中捕获所有内容而需要)。它实际上是throws Throwable,当然,你没有多少选择。

答案 1 :(得分:18)

当你说抓住var routerApp = angular.module('routerApp', ['ui.router','ngResource']); routerApp.config(function($stateProvider, $urlRouterProvider) { $stateProvider // HOME STATES AND NESTED VIEWS .state('partyDetail', { url: '/party/:partyID', 不是一个好主意时,你是对的。但是,您在问题中提供的代码并没有以邪恶的方式捕捉Throwable,而是让我们稍后再讨论。目前,您在问题中提供的代码有几个优点:

<强> 1。可读性

如果仔细查看代码,您会注意到即使catch块正在捕获ThrowableThrowable方法也会检查抛出的异常类型,并可能采取不同的操作异常类型。

您问题中提供的代码与以下内容同义:

handleException

即使你只需要捕获10多个例外,这段代码很容易占用大量的代码,而multi-catch构造也不会让代码更清晰。您在问题中提供的代码只是将try { doSomething(); } catch (SQLEXception ex){ response = handleException(resource); } catch(IllegalArgumentException ex) { response = handleException(resource); } catch(Throwable ex) { response = handleException(resource); } 委托给另一个方法,以使实际工作方法更具可读性。

<强> 2。可重用性

handleRequest方法的代码可以轻松修改并放在实用程序类中,并在整个应用程序中访问,以处理catchException。您甚至可以将方法提取为两个Error方法;一个处理private和一个处理Exception并使用Error方法进行handleException进一步委托调用这些方法的方法。

第3。 Maintainibility

如果您决定要更改在应用程序中记录Throwable的方式,则必须在单个位置进行此更改,而不是访问每个抛出{{1}的类中的每个方法}}

所以抓住SQLException一个坏主意?

您在问题中提供的代码与单独捕获SQLException的代码并不完全相同。以下代码是一个很大的禁忌:

Throwable

您应该尽可能远离Throwable链中的try { doSomething(); } catch(Throwable e) { //log, rethrow or take some action } Throwable

最后但并非最不重要,请记住,您在问题中提供的代码是框架代码,并且框架仍然可以从中恢复某些错误。有关更好的解释,请参阅When to catch java.lang.Error

答案 2 :(得分:9)

抓住Throwable出于懒惰是一个坏主意。

try-multi-catch被引入之前,这是特别诱人的。

try {
   ...
} catch (SomeException e) {
   //do something
} catch (OtherException e) {
   //do the same thing
} ...

重复捕获块是繁琐冗长的,所以有些人决定只抓住ExceptionThrowable并完成它。这是应该避免的,因为:

  1. 这使你难以理解你想要做的事情。
  2. 你最终可能会抓到很多你无法处理的东西。
  3. 如果完全吞下了挡块中的Throwable,你应该受到奖励惩罚。 (而且我们都看到了代码那样......:))
  4. 但是在绝对必要时抓住Throwable就可以了。

    什么时候需要?非常稀有。在框架式代码中有各种场景(动态加载外部类是最明显的一种),在独立应用程序中,典型的例子是在退出之前尝试显示/记录某种错误消息。 (请记住,尝试可能会失败,所以你不想在那里放任何关键的东西。)

    根据经验,如果您无法对异常/错误采取任何措施,则根本不应该抓住它。

答案 3 :(得分:3)

您发布了一个指向Jongo的链接,该链接演示了此技术的一种可能用途:重新使用错误处理代码。

假设您有一大块错误处理代码,它们会在代码中的不同位置自然重复 - 例如Jongo会为某些标准类错误生成标准响应。将错误处理代码提取到方法中可能是个好主意,因此您可以从所需的所有位置重复使用它。

然而,这并不是说Jongo的代码没有任何问题。

抓住Throwable(而不是使用群集)仍然存在疑问,因为您可能会抓住Error您无法正常处理的事情(您是否确定?) 你打算抓住ThreadDeath?)。在这种情况下,如果你必须抓住Throwable,最好“捕捉和释放”(即重新抛出任何你不想抓住的东西)。 Jongo没有这样做。

答案 4 :(得分:3)

使用庞大网络有两个有效用途:

在这两种情况下,除非您预期该异常并完全处理,否则请重新抛出。

答案 5 :(得分:2)

首先,捕获Throwable会使您的应用程序变得不透明。在特殊情况下,您应该尽可能明确地捕获异常以实现良好的可追溯性。

让我们看看方法handleException(...),看看这种方法出现的一些问题:

  • 你抓住了Throwable,但你只处理异常,如果例如抛出类型为Error的OutOfMemoryError? - 我发现坏事要发生......
  • 关于使用instanceof进行良好的面向对象编程,打破了Open-Closed-Principle并使代码更改(例如添加新的异常)非常麻烦。

从我的角度来看,catch-blocks正是针对handleExceptions(...)中试图覆盖的功能而设计的,所以请使用它们。

答案 6 :(得分:2)

Java 7解决了一些繁琐的问题,这些繁琐程序具有类似处理的类似异常。你绝对不应该做这个人在这里所做的事情。只是根据需要捕获适当的异常,它可能看起来很难看,但那就是throws的用途,将它传递给应该捕获它的方法,你不应该浪费太多的代码空间

Check out this link for more information.

答案 7 :(得分:2)

只是为了提供平衡 - 有一个的地方,我将永远catch (Throwable)

public static void main(String args[]) {
    try {
        new Test().test();
    } catch (Throwable t) {
        t.printStackTrace(System.err);
    }
}

至少有些东西显示某些地方出了问题。

答案 8 :(得分:0)

您可以随时捕获不同类型的异常,并根据您获得的异常类型执行某些操作。

这是一个例子

          try{

              //do something that could throw an exception

             }catch (ConnectException e) {
                //do something related to connection


            } catch (InvalidAttributeValueException e) {
                // do anything related to invalid attribute exception

            } catch (NullPointerException e) {

                // do something if a null if obtained
            }

            catch (Exception e) {
            // any other exception that is not handled can be catch here, handle it here

            }
            finally{
          //perform the final operatin like closing the connections etc.
             }