zoukankan      html  css  js  c++  java
  • Java Magic. Part 3: Finally

    Java Magic. Part 3: Finally

    @(Base)[JDK, magic, 黑魔法]

    转载请写明:原文地址

    英文原文

    系列文章:

    -Java Magic. Part 1: java.net.URL
    -Java Magic. Part 2: 0xCAFEBABE
    -Java Magic. Part 3: Finally
    -Java Magic. Part 4: sun.misc.Unsafe

    所有JAVA程序员都应该知道一个基本概念-finally一定会被执行,但是真的是这样么?

    这取决于“执行”是什么意思。但总的来说答案都是,YES。

    Normal program execution

    有人可能拿如下的例子来反驳:

    try {
      System.exit(1);
    } finally {
      System.out.println("I'm here, man");
    }
    

    刚才是不是你说的finlly块一定会被执行。

    显然在上面这个例子中,Sout语句不会被执行。我们刚才也说了,是正常的程序六层中答案是肯定的。

    下面这句话来自官方文档

    Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute.

    我们再看下面这段代码,第二行是不是一定会执行呢?

    Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute.
    

    答案仍然是肯定的。除非...BANG...断电了,程序终止。

    这是神马意思呢?意思就是程序非正常的运行。我们没办法保证所有事情。显然,这和System.exit(1)是一个意思,也和你电脑上的重启键是一个意思。

    所以我们不讨论这种情况啦。没劲。

    Perpetuum Mobile

    永动机 我们再来看如下代码:

    try {
      while (true) {
        System.out.println("I print here some useful information");
      }
    } finally {
      System.out.println("Let me run");
    }
    

    这里的finlly块会执行吗?当然可能,就是在标准输出异常的时候。但是绝大部分情况答案仍然是不会。

    Threads

    什么是线程?我们都知道线程的执行流程可以被interrupted。

    假设我们有一个线程正在执行一些东西,另外一个线程kill掉当前线程(此时他正要执行finally)。

    还有一个场景是,如果两个线程之间有死锁,那么还是不会执行finally块的。

    下面这段话仍然来自官方文档

    ...if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.

    所以这种情况下,我们可以把线程当做一个独立的程序来看:

    Finally块肯定是会执行的。除了程序或者线程异常的终止了。

    Finally we return

    好了,根据上述的文字,我们了解了finally一定会被执行。但是你知道finally什么时候会被执行吗?

    考虑如下代码:

    int someFunc() {
      try {
        return 0;
      } finally {
        return 1;
      }
    }
    

    这个返回值是多少呢? 返回值是1。因为finally一定会被执行。

    考虑下面这段呢?

    int someFunc() {
      try {
        throw new RuntimeException();
      } finally {
        return 1;
      }
    }
    

    答案仍然是1。但是有个问题是,异常就被吞掉了。这个场景是一个非常有名的场景,叫做exception swallowing。这是一个非常危险示例,因为client的代码以为你会返回一个值或者抛出一个异常,但是你永远都只是返回一个值。

    下面我们最后看一个类似的例子:

    String deposit(int amount) throws DAOException {
      try {
        return dao.deposit(amount);
      } finally {
        return "OK";
      }
    }
    

    dao.deposit会抛出一个受检的异常,导致客户端必须处理这个异常,但是呢,由于上面我们已经提到的原因,这个函数又永远返回OK,是不是有点淡淡的忧伤。

    所以我们得到另外一个结论:

    永远不要在finally里面使用return语句。

    Instead of conclusion

    很多程序员已经意识到finally的一些问题。但根据我们上面说的,只需要注意两点就可以避免犯错~

    • Rule 1 Finally executes always, except the case where controlling program or thread was aborted.
    • Rule 2 Never use return from finally block.
  • 相关阅读:
    git使用记录
    【转】话说我打算一天学完object c语法,系列1--------来自书Objective-c程序设计
    【转】看源代码那些事
    中英文对照 —— 数学定律定理(公式及其描述)
    CUDA+OpenGL混合编程
    简明欧洲史
    简明欧洲史
    CUDA一维纹理内存
    CUDA中的常量内存__constant__
    CUDA线程协作之共享存储器“__shared__”&&“__syncthreads()”
  • 原文地址:https://www.cnblogs.com/maxmys/p/5183964.html
Copyright © 2011-2022 走看看