【问题标题】:Multiple or Single Try Catch [duplicate]多次或一次尝试捕获[重复]
【发布时间】:2010-12-29 15:23:41
【问题描述】:

我正在清理我的一些代码,但我不确定哪条路线会更好。

目前,我的大部分方法都有一个 try catch 块,它在最后处理一些单独的异常,但我认为拥有更多的 try catch 块会更好地进行维护。然而,在分解代码时,我发现我正在为同一类型的异常编写多个块。我可以看到为每个部分编写一个块的好处,因为我可以详细说明它失败的原因。

我的问题是……这样做有缺点吗?会不会有性能问题或其他一些我没有看到的隐藏怪物?

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

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

//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
}

【问题讨论】:

  • 似乎你觉得你需要为每个抛出的异常写一条错误消息,接近它被抛出的地方。但为什么?通常唯一重要的信息是整个操作失败了。
  • @Raedwald:我觉得添加更多关于操作失败原因的信息对于在我之后工作的人的维护很有用。我正在使用一些开源插件,因此对于不了解它们的人,我可以添加更多细节。
  • 这就是日志记录如此重要的原因,Shaded。如果正如 Raedwalk 所建议的那样,无论如何恢复都是无望的,那么您不必加载带有特定错误处理的代码。我的一般技术是记录我认为重要的任何内容并重新抛出异常。事实上,如果错误是无望的,我会重新抛出一个运行时异常并在最高级别捕获它以进行最终清理。
  • 在大多数情况下,堆栈跟踪和异常对象的字符串表示应该足以为维护程序员指明正确的方向。他们可以访问源代码,因此没有任何理由重复可以从那里收集的信息。
  • 这能回答你的问题吗? Multiple try-catch or one?

标签: java exception-handling coding-style


【解决方案1】:

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

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

这比拥有多个 try/catch 更具可读性。请注意,您的方法应该本着自我记录代码的精神来描述它们所做的事情。

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

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

【讨论】:

  • 非常好,我想我会尝试重构(正如所有回复的人都建议的那样)并将其中的一些混乱分解到不同的类中。
  • 在重构时要小心,不要改变代码的行为。例如,如果在你有两个 try/catch 块之前,比如 A 和 B,并且 A 中的代码在没有重新抛出的情况下被处理,那么 B 中的代码将被执行。如果您只是将两个这样的块合并为一个,则如果 A 抛出异常,则此行为将发生变化,则 B 将不再执行。祝重构愉快!
  • 我有一个问题,如果我们在 catch 块中捕获一个广义异常,即异常以及这些异常,该怎么办? ...代码会正确执行吗?还是所有异常都将转到捕获顶级异常“异常”的catch块?还是会有某种编译时/运行时异常?
  • 如果我需要具有相同异常的不同输出消息怎么办?
【解决方案2】:

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

假设我写:

场景 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 子句中,不显示常量字符串,而是显示 SomeException.toString 或 SomeException.getMessage。

【讨论】:

  • 很好,但是在我目前的情况下,任何异常都会停止操作并抛出更高级别以继续运行。
  • 那你不能有两个小渔获物。它行不通。如果第一个 try 块遇到异常,仍然会执行第二个 try 块。
  • 完美,事实上我正是在寻找要解决的这两种情况
  • 此答案应标记为解决方案,因为它清楚地回答了问题。
【解决方案3】:

如果可以以不同方式处理异常(不同的错误消息等),那么单独捕获它们就可以了。

如果 Exception 类型不同,这并不意味着你必须有单独的 try 块,你可以有一个 try 块和多个 catch。

【讨论】:

  • 是的,但我想要更多,如果在一个 try 块中我有两行都抛出相同类型的异常。
  • 如果您以不同的方式处理它们,那么最好有两个 catch 块。但它确实提出了许多其他答案所追求的问题。
  • 我完全同意,不过感谢您从不同的角度回答问题:D
【解决方案4】:

这完全取决于场景。如果你做了一堆引发安全异常的事情,并且以同样的方式处理这种情况,你可以为此使用 try 块。

不过,话虽如此,在我看来,使用许多较小的 try/catch 块通常会更好。使用一个大的 try/catch 就像使用几个 goto 语句,只是你不知道这些 goto 是从哪里来的。

例如,在下面,您如何判断哪个方法会转到异常 1,哪些会转到异常 2?小块没问题,大了就很难读了。

try{
  doThing1();
  doThing2();
  doThing3();
  doThing4();
  doThing5();
  doThing6();
  doThing7();
  doThing8();
  doThing9();
} catch (Exception1 e){

} catch (Exception2 e){

}

下面更清楚了。

try{
  doThing1();      
} catch (Exception1 e){ [...] } 
  doThing2();
  doThing3();
  doThing4();
  doThing5();
  doThing6();
  doThing7();
  doThing8();
try{
    doThing9();
} catch (Exception2 e){ [...] }

【讨论】:

    【解决方案5】:

    我个人的偏好是一次尝试,可能有也可能没有多个 catch 块。在有意义的情况下,我的方法往往足够小。如果你的时间太长而无法实现,也许你需要考虑重构。

    关于 catch 块的一件事:如果您的 catch 块打印或记录堆栈跟踪并重新抛出,我会说您最好将异常添加到方法签名中的 throws 子句并让它冒泡.

    【讨论】:

      【解决方案6】:

      我同意上述答案的普遍共识,即单个 try-catch 块更好。但是,当您的方法足够长可以让您查看这个问题时,它可能已经太长了。如果异常处理更加本地化,​​那么从中提取新方法可能会更容易。不过,我认为您最好的选择可能是在原始方法中提取简单地抛出异常并保留异常处理的方法 - 理想情况下在单个 try-catch 块中。

      【讨论】:

        【解决方案7】:

        这看起来很老的问题。但是,我的回答会让它变得无关紧要,因为最近几天 Java 7 添加了新功能来添加多个异常和 catch 块。这将消除大量代码并且看起来非常有趣。我遇到了这个link 解释try-with-resource 的概念。

        【讨论】:

          【解决方案8】:

          很好的问题。我要说你应该使用一个 try-catch 块。我的理由:如果您有理由将您的方法划分为多个 try-catch 块,您可能应该考虑将您的方法重构为多个方法,每个方法都有自己的单个 try-catch 块。

          【讨论】:

            【解决方案9】:

            我尽量避免重复代码。所以如果对某种异常的响应是一样的,那么就捕获一次。

            【讨论】:

              【解决方案10】:

              我更喜欢单个 try-catch 块。如果方法的长度增长很多,那么我更喜欢将方法分成多个内部方法以实现模块化。
              有时您也可以重复使用这些内部方法。
              我觉得这种方式更清洁,更便于维护。

              【讨论】:

                【解决方案11】:

                这取决于您的代码逻辑 - 您是否可以随时中断您的流程(计算或其他),或者您可以/应该/需要/必须控制流程和回滚/通知/验证/whateverify 如果某些错误条件由异常指示在特定步骤。

                如果您正在实现简单的 RSS 客户端,您可以将所有与套接字相关的代码放在一个块中。但是如果你正在编写 bittorrent 客户端,你将需要状态机和更精细的异常处理。

                【讨论】:

                  【解决方案12】:

                  为了安全起见,请始终为每个抛出异常的语句使用单独的 try catch 块,因为如果您将所有内容都写在一个 try 块中,那么如果任何语句抛出异常,那么写在它下面的语句将不会被执行。

                  【讨论】:

                    【解决方案13】:

                    我可以看到这个问题的每个答案都很好,但是没有人在java 中使用层次结构的概念。如果您使用以下方法,则无需具体捕获任何异常:

                    try {
                    
                        //your code
                    
                    }
                    catch(Exception e) {
                    
                        System.println(e.getCause());
                    
                    }
                    

                    您正在捕获所有这样的异常,因为所有其他异常都在扩展抽象类Exception……所以任何异常都会被捕获!

                    我希望这有助于清除图片。

                    【讨论】:

                      猜你喜欢
                      • 2013-08-26
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-02-12
                      • 2017-11-24
                      • 1970-01-01
                      • 2011-08-31
                      相关资源
                      最近更新 更多