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.

Java Magic. Part 3: Finally的更多相关文章

  1. Java Magic. Part 4: sun.misc.Unsafe

    Java Magic. Part 4: sun.misc.Unsafe @(Base)[JDK, Unsafe, magic, 黑魔法] 转载请写明:原文地址 系列文章: -Java Magic. P ...

  2. Java Magic. Part 2: 0xCAFEBABE

    Java Magic. Part 2: 0xCAFEBABE @(Base)[JDK, magic, 黑魔法] 转载请写明:原文地址 英文原文 系列文章: -Java Magic. Part 1: j ...

  3. Java Magic. Part 1: java.net.URL

    Java Magic. Part 1: java.net.URL @(Base)[JDK, url, magic, 黑魔法] 英文原文 转载请写明:原文地址 系列文章: -Java Magic. Pa ...

  4. Magic Cast Method in Java Magic Trick In Java

    https://www.atlassian.com/blog/archives/magic_trick_in_java https://www.gamlor.info/wordpress/2010/1 ...

  5. 【Java并发】详解 AbstractQueuedSynchronizer

    前言 队列同步器 AbstractQueuedSynchronizer(以下简称 AQS),是用来构建锁或者其他同步组件的基础框架.它使用一个 int 成员变量来表示同步状态,通过 CAS 操作对同步 ...

  6. 【java编程】Java魔法类:Unsafe应用解析

    转载来源:https://tech.meituan.com/2019/02/14/talk-about-java-magic-class-unsafe.html 前言 Unsafe是位于sun.mis ...

  7. Java sun.misc.unsafe类

    Java是一个安全的开发工具,它阻止开发人员犯很多低级的错误,而大部份的错误都是基于内存管理方面的.如果你想搞破坏,可以使用Unsafe这个类.这个类是属于sun.*API中的类,并且它不是J2SE中 ...

  8. Java并发编程-Unsafe实现原理与Unsafe应用解析

    前言 Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别.不安全操作的方法,如直接访问系统内存资源.自主管理内存资源等,这些方法在提升Java运行效率.增强Java语言底层资源 ...

  9. sun.misc.unsafe

    Java中大部分错误都是基于内存管理方面的.如果想破坏,可以使用Unsafe这个类. 实例化Unsafe: 下面两种方式是不行的 private Unsafe() {} //私有构造方法 @Calle ...

随机推荐

  1. Linux 下V4l2摄像头采集图片,实现yuyv转RGB,RGB转BMP,RGB伸缩,jpeglib 库实现压缩RGB到内存中,JPEG经UDP发送功(转)

    ./configure CC=arm-linux-gnueabihf-gcc LD=arm-linux-gnueabihf-ld --host=arm-linux --prefix=/usr/loca ...

  2. Java Web Service 学习笔记

    一.服务端 1. 创建Java工程 2. 创建接口HostipalServiceInterface package ws_server; import javax.jws.WebMethod; imp ...

  3. C# DateTime 月第一天和最后一天 取法

    取得某月和上个月第一天和最后一天的方法 /// <summary> /// 取得某月的第一天 /// </summary> /// <param name="d ...

  4. make_heap()等函数的用法

    1.make_heap() make_heap()用于把一个可迭代容器变成一个堆,默认是大顶堆. 它有三个参数.第一个参数是指向开始元素的迭代器,第二个参数是指向最末尾元素的迭代器,第三个参数是les ...

  5. bzoj2035: [2009国家集训队]数据读取问题

    Description Input Output 可以转为边权为1的最短路:将不修改并读取x个数看作有向边,原先树上的边仍保留且视为双向边(但从根出发的边为单向)表示上次读取的修改 第一种边是点到bf ...

  6. HttpURLConnection连接超时问题

    1.问题描述 这几天测试重构后的下载框架,发现在下载过程中如果网络中断或网络较差,个别应用的下载就会阻塞卡住,一直卡在 “正在下载 xx%”.   2.问题排查和定位 思考:网络差不应该报网络异常的错 ...

  7. css 元素选择器实例

    一个完整的HTML页面是有很多不同的标签组成,而标签选择器,则是决定哪些标签采用相应的CSS样式.本文章向码农介绍css 标签/元素选择器以及其实例,需要的码农可以参考一下. [标签选择器] 一个完整 ...

  8. gz文件最后四位检测

    [root@node-0 ~]# ll -rw-r--r--  1 root root 24048 Nov 29 11:29 install.log 文件大小为24048 [root@node-0 ~ ...

  9. Flash和滚动字幕

    flash 1.插入flash     1)<object>             <embed src="路径"></embed>      ...

  10. Coxph model Pvalue Select2

    4   1) Put summary(coxphobject) into a variable summcph <- summary(coxphobject) 2) examine it wit ...