多次或单次尝试捕获

时间:2010-12-29 15:23:41

标签: java exception-handling coding-style

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

目前我在我的大多数方法上都有一个try catch块,它最后处理了一些单独的异常,但我认为有更多尝试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
}

13 个答案:

答案 0 :(得分:50)

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

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

这比具有多个try / catches更具可读性。请注意,您的方法应该根据自我记录代码的精神描述它们的作用。

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

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

答案 1 :(得分:46)

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

假设我写道:

情景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失败,那么仍然应该执行toThingB吗?

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

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

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

答案 2 :(得分:4)

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

如果异常类型不同,这并不意味着您必须拥有单独的try块,您可以拥有一个具有多个catch的try块。

答案 3 :(得分:1)

我的个人偏好是单次尝试,可能有也可能没有多个catch块。我的方法往往足够小,这是有道理的。如果你的实践太长了,或许你需要考虑重构。

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

答案 4 :(得分:1)

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

答案 5 :(得分:1)

它完全依赖于场景。如果你做了一堆引发安全异常的东西并且你以同样的方式处理那个场景,你可以使用try块。

然而,话虽如此,在我看来,使用许多较小的try / catch块通常更好。使用一个大的try / catch就像使用几个goto语句,除了你不能告诉gotos来自哪里。

例如,在下面你怎么知道哪个方法会转到exception1哪个方法会转到异常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){ [...] }

答案 6 :(得分:0)

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

答案 7 :(得分:0)

我尽量避免重复代码。因此,如果对某种类型的异常的响应相同,则捕获一次。

答案 8 :(得分:0)

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

答案 9 :(得分:0)

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

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

答案 10 :(得分:0)

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

答案 11 :(得分:0)

为了安全,总是为每个异常抛出语句使用单独的try catch块,因为如果你在一个try块中写入all,那么如果任何语句抛出异常,则不会执行在其下面写的语句。

答案 12 :(得分:0)

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

try {

    //your code

}
catch(Exception e) {

    System.println(e.getCause());

}

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

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