多个特定捕获或一个捕获所有?

Pab*_*era 7 java exception-handling

我见过有时这个话题出现在过去,但即使谷歌搜索后,这件事,我仍然无法弄清楚什么是对付它的好和优雅的方式,所以在这里不言而喻.

假设我有一些引发各种异常的代码......

try {
  /* some code that throws these exceptions */
} catch (NoSuchAuthorityCodeException e) {
    throw new MyAPIException("Something went wrong", e);
} catch (FactoryException e) {
    throw new MyAPIException("Something went wrong", e);
} catch (MismatchedDimensionException e) {
    throw new MyAPIException("Something went wrong", e);
} catch (TransformException e) {
    throw new MyAPIException("Something went wrong", e);
}
Run Code Online (Sandbox Code Playgroud)

......正如我们所看到的,我只是将这些异常包装起来并抛出一个新的异常,说明我的API中出了问题.

在我看来,这是一个过于重复的代码,因此只需捕获一个Exception类型并处理它并将其抛出一个新的代码.

try {
  /* some code that throws these exceptions */
} catch (Exception e) {
    throw new MyAPIException("Something went wrong", e);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它保持更简单,但问题是我们也会捕获每个RuntimeException.鉴于此,我们可以捕获 - 重新抛出RuntimeException,以便我们可以避免这种情况.

try {
  /* some code that throws some exceptions */
} catch (RuntimeException e) {
    throw e;
} catch (Exception e) {
    throw new MyAPIException("Something went wrong", e);
}
Run Code Online (Sandbox Code Playgroud)

它有点笨重,但它的确如此.现在关于catch(Exception e)的另一个小问题是,如果我的内部API抛出另一个MyAPIException,它也会被捕获,包装并在另一个MyAPIException中抛出.在这种特殊情况下,我们也可以捕获MyAPIException并重新抛出它.

try {
  /* some code that throws some exceptions */
} catch (RuntimeException e) {
    throw e;
} catch (MyAPIException e) {
    throw e;
} catch (Exception e) {
    throw new MyAPIException("Something went wrong", e);
}
Run Code Online (Sandbox Code Playgroud)

好吧,它再次变得混乱,但在这种情况下,我们阻止包装MyAPIException并简单地重新抛出它.但是,还有另一个问题,即catch(Exception e)块,如果内部API发生变化并开始抛出另一种异常(除了上面提到的这些之外的一些),编译器就不会对它有任何意义而且我们不会我有一个线索.这不是一个主要问题,因为我可能会以同样的方式对待它.

在这种情况下,我认为问题是,哪一个更好,有更好的选择吗?

emo*_*ory 5

由于您使用Java5并且使用专有异常,为什么不将所有异常逻辑放入异常类中.

使用率

try
{
     // some code that might throw one of several exceptions
}
catch ( Exception cause )
{
     MyAPIException . handle ( cause ) ;
}
Run Code Online (Sandbox Code Playgroud)

MyAPIException包含逻辑

class MyAPIException extends Exception
{
    private MyAPIException ( String message , Throwable cause ) { super ( message , cause ) ; }

    private static void myAPIException ( Exception cause ) throws MyAPIException
    {
         throw new MyAPIException ( "Something Went Wrong" , cause ) ;
    }

    public static void handle ( Exception e ) throws MyAPIException
    {
          try
          {
               throw ( e ) ;
          }
          catch ( RuntimeException cause )
          {
                throw cause ;
          }
          catch ( MyAPIException cause )
          {
                 throw cause ;
          }
          catch ( NoSuchAuthorityCodeException cause )  // repeat for other exceptions
          {
                 myAPIException ( cause ) ;
          }
          catch ( Exception cause ) // this should not happen
          {
                  assert false ; // or log it or throw a RuntimeException ... somehow signal that programming logic has failed
          }
    }
}
Run Code Online (Sandbox Code Playgroud)


bra*_*boy 2

拥有不止一个MyApiException。如果您的所有异常都为MyApiException,那么您和其他人阅读您的代码都会变得有点困难。正确命名它也至关重要。另外,您并不总是想抓住并重新扔掉它。如果是这种情况,只需声明一个throws方法签名即可。

另外,您无法修复一个简单的捕获或多个捕获。在我看来,这更多的是一个判断性的决定,因为有些例外对于更容易处理的类型来说是致命的(因为整个程序必须停止)。

throws当API 中有一堆子句时,我根本看不出有什么问题。这是一个更加简洁的实现。那么如果调用者必须处理您定义的异常怎么办?如果 API 中的某个方法可能会引发异常并且必须对此采取措施,那么调用者应该必须处理它。无论如何,该特定异常的文档必须清晰,以免使调用者感到困惑。

决定这一点的另一个因素是 API 的复杂性。不久前,我编写了一个相当复杂的 API,我必须处理与您所提出的问题相同的问题。我为少数方法编写了一些自定义异常。我确信您最终不会为 API 公开的所有公共方法抛出异常,但有些地方它们是不可避免的。

最后,如果您觉得拥有太多自定义异常是一种痛苦的选择,您可以使用一个带有明确记录的错误代码的异常。这样调用者就可以按照他认为合适的方式处理异常并处理错误代码。

  • 正如您所指出的,我们还可以针对每种情况有许多特定的异常,但在我看来,明智的做法是让所有这些异常都从 API 中的单个异常扩展。像这样,用户可以根据他/她的需要处理每种情况(特定捕获)或捕获所有情况(捕获主要 API 异常)。 (2认同)