多次或单次尝试捕获

2022-08-31 17:11:04

我正在努力清理我的一些代码,我到了我不确定哪种路线会更好的地步。

目前,我对我的大部分方法都有一个单次尝试捕获块,它在最后处理一些单独的异常,但我认为有更多的尝试捕获块对于维护会更好。但是,在分解代码时,我遇到了一个点,我正在为同一类型的异常编写多个块。我可以看到为每个部分编写一个块的好处,因为我可以更详细地说明为什么它失败了。

我的问题是这个...这样做有缺点吗?是否存在性能问题或其他我没有看到的隐藏怪物?

另外,在一种方法中处理多个异常的首选方法是什么,是否有行业标准?

为了更好地说明我的观点,这里有一些伪代码

//multiple try catch for same exception
try {
     //some code here
} catch (MyException e) {
     //specific error message here
}
try {
     //some different code here
} catch (MyException e) {
     //more specific error message indicating a different issue
}

答案 1

这不是一个性能或个人偏好问题:这是一个功能和需求问题。

假设我写:

方案 1:

try
{
  doThingA();
}
catch (SomeException panic)
{
  System.out.println("doThingA failed");
}
try
{
  doThingB();
}
catch (SomeException panic)
{
  System.out.println("doThingB failed");
}

方案 2:

try
{
  doThingA();
  doThingB();
}
catch (SomeException panic)
{
  System.out.println("doThingA or doThingB failed");
}

这两种方案并不等同:它们执行不同的事情。在场景1中,如果 doThingA 抛出异常,doThingB 仍会执行。在场景2中,如果 doThingA 引发异常,则不会执行 doThingB。因此,问题不在于哪个提供更好的性能或哪个代码更具可读性,而是,如果doThingA失败,doThingB是否仍应执行?

如果你真正想要的是第二种行为,但你想让不同的消息告诉用户出了什么问题,那么你应该抛出不同的异常,或者把消息的文本放到异常中,即

void doThingA() throws SomeException
{
  ... whatever code ...
  if (theWorldIsAboutToEnd)
    throw new SomeException("doThingA failed");
}

然后在 catch 子句中,不显示常量字符串,而是 displayt SomeException.toString 或 SomeException.getMessage。


答案 2

我总是试图降低嵌套级别以提高可读性和可维护性。如果你有n个 try/catch 块,每个块处理相同类型的异常,为什么不重构可以将异常抛出到方法中的代码...它看起来像这样:

try {
    firstBatchOfTricky();
    secondBatchOfTricky();
    ....
    nthBatchOfTricky();
} catch (ItWentBoomException e) {
   // recover from boom
} catch (ItWentBangException e) {
   // recover from bang
}

这比具有多个尝试/捕获更具可读性。请注意,您的方法应本着自我记录代码的精神描述它们的作用。

由于您有自己的 Exception 类型,因此可以将所需的数据添加到 Exception 中,以便在 catch 块中执行不同的操作。当你说“更具体的消息”时,你可以随详细消息一起抛出异常;你不应该需要多个捕获块。如果你想根据异常的状态做完全不同的事情,只需创建更多的异常类型并捕获块,但只有一个尝试块,正如我的伪代码所示......

最后,如果无法从异常中恢复,则不应使用 catch 块使代码混乱。引发运行时异常并让它冒泡。(评论中@tony的好建议)