java中的“try - catch -finally”结构中的“finally”都有哪些用途

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中的“try - catch -finally”结构中的“finally”都有哪些用途相关的知识,希望对你有一定的参考价值。

编程人员一般都用finally做些什么事情

可以这么理解
try块中的内容是在无异常发生时执行到结束
catch块中的内容,是在try块中内容发生catch所声明的异常时,跳转到catch块执行
finally块则是无论是否发生异常,都会执行finally块的内容
所以,代码逻辑中有需要无论发生什么都必须执行的代码,则可以放在finally块中
例如:最常见的就是把关闭connection、释放资源等的代码放在finally块中
参考技术A 无异常执行 try
有异常执行catch
不管有无异常都要执行 finally
finally的作用用来关闭流、关闭连接、释放或销毁资源。
参考技术B 参考一下面实体的标准答案:

题目: final, finally, finalize的区别。

答案:

final修饰符(关键字),如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载。方法的参数被final修饰表示在方法体内,该参数的值不可以被修改。

private final String ss = "ss";

public final void m()



public String m2(final String param)



finally在异常处理时提供finally块来执行任何清除操作。无论有没有异常被抛出、捕捉,finally块都会被执行。

finalize是方法名。Java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在Object类中定义的,因此所有的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。
参考技术C 我也是刚刚才看了关于finally的,上面介绍说是为了放置清理代码。

为啥在 Try ... Catch 中使用 finally

【中文标题】为啥在 Try ... Catch 中使用 finally【英文标题】:Why use Finally in Try ... Catch为什么在 Try ... Catch 中使用 finally 【发布时间】:2010-11-12 14:53:30 【问题描述】:

我看到Try .. Catch 中的Finally 将始终在try catch 块执行的任何部分之后执行。

跳过 Finally 部分然后在 try catch 块之外运行它有什么不同吗?

示例 1,Try ... Catch ... Final ... End Try

​​>
    Try
        'Do something
    Catch ex As Exception
        'Handle exception
    Finally
        'Do cleanup
    End Try

示例 2,Try ... Catch ... End Try ... 在外面做 finally 的东西

    Try
        'Do something
    Catch ex As Exception
        'Handle exception
    End Try
    'Do cleanup

【问题讨论】:

【参考方案1】:

最后应该习惯于为了保持系统的一致性而需要做的所有事情。这通常意味着释放资源

无论抛出什么异常,Final 总是被执行。它应该用于释放资源,在以下情况下:

完成连接 关闭文件处理程序 空闲内存 关闭数据库连接

让我举一个完整的例子。想象一下,您正在通过网络发送消息。在伪代码中:

// With finally                  |  //Without finally
try                             |  try  
  send_message()                 |    send_message() 
 catch(NetworkError)           |   catch(NetworkError) 
  deal_with_exception()          |    deal_with_exception()
 finally                       |  
  finalizes_connection()         |  finalizes_connection() 
                                |

这两个代码的唯一区别是当 try 块中的内容引发不是 NetworkError 的异常时,例如 MethodNotFound。第一种情况会调用方法finalizes_connection(),而第二种情况不会。

连接自然是通过多个程序完成的。那么在另一个程序出现MethodNotFound 异常的情况下会发生什么?在第一种情况下,您的程序将完成连接和另一个程序,它会很高兴。在第二种情况下,另一个程序可能会永远等待您的响应。如果另一个程序每次只能接收一个连接怎么办?你刚刚也窃听了另一个程序。

这也适用于文件,例如,您打开而其他程序将无法打开以供阅读(在 Windows 中)。而对于内存,它永远不会被释放,现在你有内存泄漏。

【讨论】:

如果您只捕获特定的异常类型,这很明显,但在我的示例中,我捕获了 Exception 类型的异常,这实际上是 any 的异常 类型。那么finally的需求就不是很明显了,不过这个别人回答的很好。【参考方案2】:

我经常使用的是(我把它封装成一个方面,但这是我派生的方面):

public static DoLengthyProcessing(this Control control, Action<Control> action)

    Cursor oldCursor = control.Cursor
    try
    
        control.Cursor = Cursors.WaitCursor;
        action(control);
    
    catch (Exception ex)
    
        ErrorHandler.Current.Handler(ex);
    
    finally
    
        control.Cursor = oldCursor;
    

或者,使用 AOP(就像我一样)。

【讨论】:

【参考方案3】:

无论函数是否因异常而退出,Finally 块都会执行。 (此规则有一些例外情况,see this *** question 了解更多信息)。

例如:

Try
    'Do something
Catch ex As Exception
    if 'Some Condition
       throw ex
    else
       'Handle exception
Finally
    'Do cleanup
End Try

在这种情况下,Finally 块仍将执行,即使您可能会从函数中抛出异常。

这是一个很好的实践,因为它可以确保您的清理代码始终执行。当然,使用Resoource Acquisition Is Initialization 成语是确保资源得到清理的一种更清洁的方法,但我对 VB.net 的了解不够,不知道这是否可行。

【讨论】:

“总是”? finally 块无法运行的原因有很多。 @Nick:请注意,finally 块并非保证始终运行;此规则有一些例外(!); ***Exception 就是其中之一。 在try块中间拔掉电脑也会导致finally不执行:) 如果执行到达外部范围,则所有内部 finally 块都保证已“运行”[尽管有些可能由于异常而提前退出]。请注意,在 vb.net 或 CIL 中,外部 try 块可能包含将从嵌套 finally 块的上下文中运行的代码,尽管 C# 不公开此类功能。至于 RAII,vb.net 和 C# 可以通过 using 构造将该概念应用于局部变量,但不能将其有效地应用于字段。 他们确实应该添加一个 PlugPulled 异常。还有一个 NotPluggedIn 异常,只是为了处理所有可能发生的情况。 *** 异常当然应该重定向到这个站点。【参考方案4】:

据我所知,我从未在我的 .NET 代码中使用过 try/catch/finally 块。

一般来说,很少需要在中间层捕获异常。异常通常传播到表示层中的***处理程序(并且可能在层边界处捕获并重新抛出,以便记录它们)。

因此,在中间层,您会更频繁地看到 try/finally(或“使用”语句),以便清理资源。并在表示层的***处理程序中的 try/catch 中。

在我既需要捕获异常又需要进行一些清理的极少数情况下,我更愿意进行重构,以便以下内容:

try

    ... do something

catch

   ... handle exception

finally

   ... cleanup

变成:

try

    DoSomethingAndCleanup();

catch

   ... handle exception


...
private void DoSomethingAndCleanup()

    try
    
        ... do something
    
    finally
    
        ... cleanup
    

恕我直言,这更干净。

【讨论】:

如果原始异常是由在内部代码中确实有意义但在表示层中没有意义的东西引起的,则中间层中的 Cathcing 异常是有意义的。然后抛出一个异常来提供有关实际错误的上下文的更多详细信息是有意义的。 太糟糕了,没有解决异常的借口,没有惯用的方法来响应异常。方法将对象暂时置于损坏状态但然后在它们返回之前修复它是很常见的。此类代码应由try 块保护,如果发生意外异常,该块将明确使对象无效; catch 似乎很恶心,一个不希望解决的异常,但我不确定 C# 中会存在什么替代方案。【参考方案5】:

看了上面对我评论的回复后,我想到了一些事情。

如果不知道问题的代码,这个问题基本上不能完全回答。

原因是并非所有代码都可以放在 finally 块中。例如。在 finally(和 catch)块中不允许使用 yield 语句。 try 块可能有几个执行分支,其中一些返回而一些不返回。 finally 在所有这些情况下都被执行,而在没有 finally 的示例中,清理代码不会出现这种情况。此外,您不能跳转(转到)到 finally 块,尽管非常罕见,您可以在 catch 块之后跳转到代码。你也不能从 finally 块返回。

在很多情况下,答案取决于实际代码。

【讨论】:

我同意不是所有在 try 块之后执行的代码都应该在 finally 块中。我的问题主要是为了澄清技术差异是什么,这在此处的最佳答案中得到了很好的回答。【参考方案6】:

带有四个单选按钮的代码:

尝试返回 在 CATCH 中返回 投掷 CATCH

完成捕捉

private void checkFinally()

    try
    
        doFinally();
    
    catch
    
        Console.WriteLine(" Breaking news: a crash occured. ");
    


private void doFinally()

    Console.WriteLine(" ");
    Console.Write("Here goes: " 
        + (radioReturnInTry.Checked ? "2. Return in try: " 
                : (radioReturnInCatch.Checked? "3. Retrun in catch: "
                    : (radioThrowInCatch.Checked? "4. Throw in catch: "
                        : "1. Continue in catch: "))) );
    try
    
        if (radioReturnInTry.Checked)
        
            Console.Write(" Returning in try. ");
            return;
        
        Console.Write(" Throwing up in try.  ");
        throw new Exception("check your checkbox.");
    
    catch (Exception ex)
    
        Console.Write(" ...caughtcha! ");
        if (radioReturnInCatch.Checked)
        
            Console.Write("Returning in catch. ");
            return;
        
        if (radioThrowInCatch.Checked)
        
            Console.Write(" Throwing up in catch. ");
            throw new Exception("after caught");
        
    
    finally  Console.Write(" Finally!!"); 
    Console.WriteLine(" Done!!!"); // before adding checkboxThrowInCatch, 
    // this would never happen (and was marked grey by ReSharper)



输出:

如下: 1. 继续捕获:尝试抛出。 ...抓到!最后!!完成!!! 这里是: 2. 在尝试中返回:在尝试中返回。终于!! 如下: 3. 在捕获中返回:在尝试中抛出。 ...抓到!抓回来。最后!! 在这里: 4. 投掷:投掷尝试。 ...抓到!追上来。最后!!突发新闻:发生了崩溃。

总结一下: 最后处理两件事:

    在 try 或 catch 中返回的代码。 或者如果你在 try 中有异常,并且在 catch 中抛出异常, 或者,如果您在尝试中遇到异常,并且没有捕获到该异常,

最后总结一下“FINALLY”最后如果你尝试过并没有什么特别的,并且

    没有返回, 并在试用期间发现任何异常,然后 也没有在捕获中返回,并且 没有抛出或有抛出的代码。

最后但并非最不重要的(最后): 如果你的代码中有一个你没有捕捉到的异常,你的代码会飞起来,而不会到达最后。

希望这很清楚。 (现在是我...)

莫舍

【讨论】:

懒得阅读和比较条件。要是有人能把它转换成表格就好了!!【参考方案7】:

除了其他人所说的之外,从语义上讲,我认为它们是不同的。

finally 块中的代码清楚地表明您正在为 try-catch 中包含的内容执行终结类型的任务。我认为这使阅读更清晰。

【讨论】:

我完全同意你的看法。我只是好奇这是否有任何技术差异,根据其他人的说法,它是......【参考方案8】:

最后包含需要在所有条件下评估的代码[无论是否发生异常]。

如果不执行 finally 块,就无法退出 try 块。如果 finally 块存在,它总是执行。 (此语句适用于所有意图和目的。有一种方法可以在不执行 finally 块的情况下退出 try 块。如果代码从 try 块中执行 System.exit(0); ,则应用程序将在没有 finally 的情况下终止另一方面,如果在 try 块期间拔掉机器,finally 也不会执行。)

主要用于处理对象。当你想关闭用户时它会很有用 定义的资源,如文件,打开的资源(db stmts)。

编辑

在 *** 异常之后也不会执行 finally。

【讨论】:

如果出现 ***Exception 是否会执行 finally 块? 这假定进程不会突然终止。【参考方案9】:

Catch 将在 try catch 块执行的任何部分之后运行。 Catch 在抛出异常并且 catch 块可以处理该类型的异常时运行。

finally 块是在 try 块完成时运行的块。完成,我的意思是它正常完成,或者以某种方式退出(跳出循环,从方法返回,抛出异常等)

如果将代码放在 finally 块之外并抛出异常(例如),则如果未捕获异常,则代码可能不会执行,或者在 catch 块中重新抛出,或者抛出新的异常在 catch 块中。如果你把它放在 finally 块中,它就会被执行。

基本上,清理应该放在 finally 块中。

【讨论】:

【参考方案10】:

在 finally 块中进行清理是为了确保它运行。如果 catch 块不处理异常(即它只是记录它),甚至导致另一个异常,finally 块中的代码仍然会运行。

【讨论】:

【参考方案11】:

在处理数据库连接或任何时候需要处理对象时,这是一个好主意。万一在运行查询时出现问题,您仍然可以安全地关闭连接。它还有助于清理 try/catch/finally 块之外的块无法访问的代码。

【讨论】:

【参考方案12】:

是的,它是不同的。 finally 将始终运行(除非程序崩溃)。如果函数在 try catch 块内退出,或者在 try 或 catch 中抛出另一个错误,finally 仍将执行。如果不使用 finally 语句,您将无法获得该功能。

【讨论】:

不幸的是,finally 块运行默认如果程序以各种方式崩溃。但如果你愿意,你可以覆盖它:处理 AppDomain.UnhandledException 以调用 Environment.FailFast 虽然如果你是一名 Java 程序员,那你就倒霉了:未处理的异常会执行 finally 块,而你真的无能为力。 好吧,你可以做点什么,你可以设计/编写你的代码,这样它就不会使用异常来进行流控制,也不要将 finally 块用于类似的事情。 finally 应该用于清理,这应该总是发生。 不是真的,有时 finally 可能不会被调用。就像从操作系统中止程序或计算机崩溃一样。 它不会执行的两种方式是当执行try/catch的线程停止执行或JVM终止时。所以线程可能会停止,程序的其余部分会继续,你永远不会知道(除非有好的日志/编码)它是否运行。【参考方案13】:

finally 用于清理代码,例如数据库连接或打开但需要关闭的文件。几乎所有需要执行的清理代码,无论是否出现异常

另外,您的异常处理可能需要重新抛出异常或其他异常,在这种情况下,块之后的代码将不会被执行

【讨论】:

【参考方案14】:

不同之处在于try 块中的代码会引发catch 块未捕获的异常。

通常catch 块会捕获特定类型的异常,并让其他任何东西通过。在这种情况下,finally 块仍将运行。

如果try 块中的代码returns 中的代码,finally 块也将运行。

【讨论】:

异常是否被捕获并不重要。 finally 块始终运行(排除异常情况,例如“蛮力”应用程序退出) @Rune FS:是的,但是如果捕获到异常,则 awe 的两个示例之间没有区别(除非引发更多异常,return 语句等)。如果没有被抓到,那就有的区别了。这就是敬畏所要问的。

以上是关于java中的“try - catch -finally”结构中的“finally”都有哪些用途的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 Try ... Catch 中使用 finally

异步编程的优势和难点

Java 9 中的 Maven 更新,Eclipse 中的 Java 8 中的 Maven 编译

关于JAVA 中的DOM操作

mySQL在java中的应用

Java中的ArrayList 重要方法补充