3

好吧,问题的标题说明了一切。

在介绍代码之前,我有几点要说明:

  • 如果我知道特定类型的异常发生在特定的语句集中,那么将它们全部放在单个 try 中立即放置相应的 catch 是一种好习惯吗?
  • 或者我应该将所有容易发生异常的代码放在单个代码块中,并在单次尝试之后放置所有相应的 catch 块。是否有任何与之相关的性能成本?

    {   
        try
        {
             exec();//can cause ExceptionXYZ
        }
        catch(ExceptionXYZ e){ }            
        try
        {
             exec(); //can cause ExceptionPQR
        }
        catch(ExceptionPQR e){ }
            try
        {
             exec(); //can cause ExceptionABC
        }
        catch(ExceptionABC e){ }
    }
    

那么上面的方法是好还是低于一个

    {
        try
        {
             exec(); //can cause ExceptionXYZ          
             exec(); // can cause ExceptionPQR        
             exec(); //can cause ExceptionABC
        }
        catch(ExceptionXYZ e){ }
        catch(ExceptionPQR e){ }
        catch(ExceptionABC e){ }
    }

也有可能混合上述两种模式,比如在 try 中嵌套 try关于何时使用的任何其他注意事项/要点?有一件事是肯定嵌套会使代码复杂一点。

在其他场景中还有一些其他注意事项(嵌套在 finally 块下),例如在关闭数据库 JDBC 资源时,我们必须独立处理每次关闭,以确保一次 close() 中的 NullPointerException 不会让其他资源保持打开状态:

    try
    { } 
    catch(Exception e)
    { }
    finally
    {
        if (rs != null)  //ResultSet
            try 
            {
                rs.close();
            }
            catch(SQLException se1)
            {
                se1.printStackTrace();
            }
        if(pstmt!=null)  //PreparedStatement
            try
            {
                pstmt.close();
            }
            catch(SQLException se2)
            {
                se2.printStackTrace();
            }
        if(conn!=null)   //Connection
            try
            {
                conn.close();
            }
            catch (SQLException se3) 
            {
                se3.printStackTrace();
            }   
    }

有什么想法吗?或者只是不必要地过度思考。

编辑

更多考虑/事实(过度思考:p)

  • 只是概括一下:如果有一些代码块在任何情况下都需要执行,那么我们应该将它们放在单独的 try-catch 中,并且这些 catch 块之外的任何其他代码都不应导致任何异常:

    {
       try
       {
          mustexec(); 
       }
       catch(){ }
    
       noexceptionexec();   
    
       try
       {
          mustexec();
       }
       catch() { }
    }
    
  • 确保通过 catch() 减少失败:如果我们确定某些语句集会导致特定的异常集,我们应该将这些代码行放入仅处理相应异常的尝试中,而不是将其放在外部尝试之后。因此,上述第三种情况(混合模式)可能是合适的一种:

    {
        try
        {
           exec(); //can cause ExceptionXYZ
        }
        catch(ExceptionABC){ }
        catch(ExceptionPQR){ }
        catch(ExceptionXYZ){ }
    }
    

上面的效率可能比

    {
        try
        {
           try
           {
              exec(); //can cause ExceptionXYZ
           }
           catch(ExceptionXYZ){ }
        }
        catch(ExceptionABC){ }
        catch(ExceptionPQR){ }
    }
4

9 回答 9

7

Code1 和 Code2 不等价。

try{
   exec1();
   exec2(); // if exec1 fails,  it is not executed
}catch(){}

try{
   exec1();
}catch(){}
try{
   exec2(); // if exec1 fails,  it is  executed
}catch(){}

而对于第 3 点是的。你可以混合你的代码。

于 2013-02-05T13:34:21.450 回答
3

如果我要引入一个catch块,我更喜欢让它更接近可能引发相应异常的代码,这与我声明变量更接近使用它们的位置的原因相同——即更好的可读性。因此,您的第一个示例显然更可取。

try/catch与一系列if语句结合起来并不那么干净,因为它要求代码的读者更好地理解异常处理程序块上方发生的事情:具体来说,在您的示例中,读者必须知道只有一个条件是true.

尽管有时需要在清理代码中设置异常处理程序,但通常在清理期间“丢弃”二级异常,只报告一级异常。

于 2013-02-05T13:35:02.690 回答
1

我认为您的主要关注点应该是:

  1. 代码的正确性,然后

  2. 代码的可读性。

正如其他人指出的那样,您示例中的两种形式并不意味着同一件事。很可能其中一种形式比另一种形式更正确。

如果你有两个同样正确的版本,那么最好的版本就是最易读的版本。

您无法根据此类人工示例对相对正确性或可读性做出合理的判断。所以底线是这个决定没有最佳实践规则。


假设这两个版本的代码同样正确且同样可读,使用多个 try/catch 块与使用多个处理程序的一个 try/catch 相比具有小的性能优势。这完全取决于处理异常时会发生什么。如果有多个catch块,则 JVM依次instanceof对每个catch块执行等效的操作,直到找到匹配的块(或耗尽它们)。如果您有 Ncatch个块,则最多需要执行 N 个测试。

但是,我应该强调差异很小尤其是当您认为异常应该是例外时;也就是说,在绝大多数情况下,您不需要处理异常。(如果这个假设不正确,那么您可能会遇到更大的性能问题,因为 Java 异常中最昂贵的部分通常是异常对象的构造。)

于 2013-02-05T14:02:27.377 回答
1

也可以只使用一个 try-catch,参见以下内容:

try {
    // some code that throws different exceptions
}
catch (Exception ex)            
{                
    if (ex is ExceptionA)
    {
        //do something
    }
    else if (ex is ExeptionB)
    {
        //do something
    }
}

等等

于 2013-02-05T13:34:03.497 回答
1

嵌套诗句而不是嵌套是一个设计决策。如果您可以从异常中恢复,那么嵌套似乎很好。如果异常是终端,那么不嵌套似乎很好。这是一个例子:

try
{
   try
   {
     ... code that may throw RecoverableException1 or TerminalException
   }
   catch (RecoverableException1 exception)
   {
     ... recover.  Perhaps use default values and add a log entry.
   }


   try
   {
     ... code that may throw RecoverableException2 or TerminalException
   }
   catch (RecoverableException2 exception)
   {
     ... recover.  Perhaps use default values and add a log entry.
   }

}
catch (TerminalException exception)
{
  ... log the terminal exception and terminate.
}
于 2013-02-05T13:39:44.647 回答
0

The first (and possibly) only thing you should consider is how to write the simplest and clearest code you can. Only after you have a working application which might have performance problems and you have profiled to determine you have measurable issue. The you can compare alternatives to see if one is better than another.

Until you have established you have a performance issue, I would stick to writing the simplest code you can.

Note: can you assume that if an exception is thrown in the first block you can continue as if it didn't matter, often this is not the case and it makes more sense to wrap all the code in a try/catch block.

于 2013-02-05T13:36:33.280 回答
0

正如你所写,你想多了。只需查看http://docs.oracle.com/javase/tutorial/essential/exceptions/catch.html上的官方 Oracle 文档,您就会清楚地看到处理异常的建议方法是

try {

} catch (ExceptionType name) {

} catch (ExceptionType name) {

}
于 2013-02-05T13:34:29.177 回答
0

如果没有异常,进入和离开 try/catch 的 CPU 时间为零。如果方法中有许多 try/catch 块,则将异常分派到适当的 catch 块可能会花费更多的 CPU,因为 JVM 需要在其他块中找到适当的 catch。对我来说,你在这里想多了。

于 2013-02-05T13:35:11.633 回答
0

检查try-with-resources它应该有帮助...

于 2015-09-25T10:42:40.800 回答