六个例子彻底理解finally语句块
发布日期:2021-10-10 12:51:19 浏览次数:8 分类:技术文章

本文共 4558 字,大约阅读时间需要 15 分钟。

六个例子彻底理解finally语句块

这篇博客主要弄清楚两个问题

   1. finally块中的代码是否一定会执行

   2. finally块中的代码什么时候被执行

首先开始第一个:

finally块中的代码一定会被执行么?

答案是否定的,主要有以下几种情况:

  1.try之前发生异常或者直接结束的情况.

  finally是与try , catch配套使用的,finally生效的最大的前提就是得能进行到try语句内,例如以下这种情况就属于没有进入到try然后finally不执行的情况:

int i = 5 / 0;        try {            System.out.println("Try block");        } catch (Exception e) {            System.out.println("Catch block");        }finally {            System.out.println("Finally block");        }

  2.try语句内强制退出程序

  比较好理解,如下:

try {            System.out.println("Try block");            System.exit(0);        } catch (Exception e) {            System.out.println("Catch block");        }finally {            System.out.println("Finally block");        }        //输出        Try block

finally是什么时候执行的?

先看实例:以下程序的输出结果是什么?

public static int test() {        try {            return 1;        } catch (Exception e) {            return 0;        } finally {            System.out.println("Finally block");        }    }    public static void main(String[] args) {        System.out.println(FinallyTest.test());    }

结果:

Finally block1

为何会出现这种情况?

Java语言的异常处理中,finally的作用就是为了保证无论出现什么情况,finally里面的代码一定会执行(当然并不能满足所有的情况).

由于程序执行return就意味着结束对当前函数的调用并且跳出这个函数,因此所有的必须要执行的语句都应该在return之前执行(除非遇到exit函数).因此finally块中的函数也是要在return之前执行的.

如下图:

这里写图片描述

至于进行的什么处理下文再说

再看一个实例:

public static int test() {        try {            return 1;        } catch (Exception e) {            return 0;        } finally {            System.out.println("Finally block");            return 3;        }    }    public static void main(String[] args) {        System.out.println(FinallyTest.test());    }

结果:

Finally block3

这个实例说明如果finally块内也包含return语句,那么finally内的return语句会覆盖try-catch内的return结果

再来一个例子:

public static int test() {        int result = 0;        try {            result = 1;            return result;        } catch (Exception e) {            result = 2;            return result;        } finally {            result = 3;            System.out.println("Finally block");        }    }    public static void main(String[] args) {        System.out.println(FinallyTest.test());    }

结果:

Finally block1

先不急于解释这种现象,再看一个类似的例子

public static StringBuilder test() {        StringBuilder builder = new StringBuilder("hello");        try {            return builder;        } catch (Exception e) {            return null;        } finally {            builder.append("world");            System.out.println("Finally block");        }    }    public static void main(String[] args) {        System.out.println(FinallyTest.test());    }

结果:

Finally blockhello world

对比前面两个例子是不是更加疑惑了,但其实原因特别简单:

  一个方法内部定义的变量都是存储在栈中的,当这个函数结束后,其对应的栈就会被系统回收,此时其方法内部定义的变量将不存在了,因此return在返回的时候不是直接返回方法中的变量的值,而是复制一份,然后返回.

  因此,对于前一个例子当中,由于是基本类型的数据,所有复制的是变量的数值,并且这个复制过程是在执行finally之前的,所有finally内修改基本类型的值没能生效,因为要输出的值早已经确定了

  而后一个例子中是引用类型,复制的时候只是复制的对象的地址,finally对变量进行修改的时候改变了对应的对象的属性,输出的时候按照地址获取属性,获取的是修改后的属性,所以是有影响的.

#现在知道前面的处理是啥了.如图:

这里写图片描述

是不是已将明了了一些了,那么再来看一个例子:

public static String test() {        StringBuilder builder = new StringBuilder("hello");        try {            return builder.toString();        } catch (Exception e) {            return null;        } finally {            builder.append(" world");            System.out.println("Finally block");        }    }    public static void main(String[] args) {        System.out.println(FinallyTest.test());    }

输出结果

Finally blockhello

细心的同学应该不会被坑到,finally内的修改没有生效,原因在于复制的时候不是复制的StringBuilder的地址,而是一个字符串的地址,当然也有同学会说String也是引用类型,finally内的代码修改了对应地址的数据,但是要注意String是一个不可变类,builder调用的append方法并没有对"hello"进行任何修改,之前String的地址对应的值是不会变化的.所以finally内的修改没有生效.有的同学有疑惑,关于String , StringBuilder等对象的区别请参考这篇博客:.

为了对比那再看一个例子:

static class TestEntity {        String mString;        StringBuilder mBuilder;        public TestEntity(String string, StringBuilder builder) {            mString = string;            mBuilder = builder;        }        public StringBuilder getBuilder() {            return mBuilder;        }    }    public static StringBuilder test() {        TestEntity entity = new TestEntity("hello", new StringBuilder("world"));        try {            return entity.getBuilder();        } catch (Exception e) {            return null;        } finally {            entity.getBuilder().append(" world");            System.out.println("Finally block");        }    }    public static void main(String[] args) {        System.out.println(FinallyTest.test());    }

应该已经猜到结果了

Finally blockworld world

原因上面都提到了,StringBuilder是引用类型并且是可变的,所以finally内的修改会生效.

结束~

有不足的地方欢迎指出,另外建了个新手交流Android开发的QQ群,欢迎加入.

群号:375276053

转载地址:https://blog.csdn.net/qq_26971803/article/details/52058715 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:自定义View新手实战-一步步实现精美的钟表界面
下一篇:Character , String , StringBuffer , StringBuilder , StringTokenizer 的区别

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2024年03月26日 13时14分54秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

VB.NET在WinForm中嵌入谷歌浏览器_制作全屏显示网页程序_并读取INI配置文件_根据配置文件显示不同的网页---VB.NET工作笔记016 2019-04-26
AndroidStudio_安卓原生开发_全局异常处理_并记录系统错误日志---Android原生开发工作笔记138 2019-04-26
AndroidStudio_安卓原生开发_AsyncTask异步处理使用_AsyncTaskLoader---Android原生开发工作笔记139 2019-04-26
C++基础部分_C++文件操作_二进制文件的写操作---C++语言工作笔记078 2019-04-26
C++提高部分_C++类模板对象做函数参数---C++语言工作笔记090 2019-04-26
C++提高部分_C++类模板与继承---C++语言工作笔记091 2019-04-26
AndroidStudio_安卓原生开发_什么是AndroidStudio NDK ---Android原生开发工作笔记140 2019-04-26
C#.NET学习笔记11,12---布尔表达式2组合,if语句 2019-04-26
网站制作---科讯万能搜索系统的简单实用教程 2019-04-26
网站制作---网站伪静态的介绍 2019-04-26
DISCUZ学习笔记01---discuz集成环境的搭建 2019-04-26
网络技巧---能上网但是网页打不开,网页打开速度慢解决方法 2019-04-26
数据库异常---ORA-01436: 用户数据中的 CONNECT BY loop in user data 循环 2019-04-26
数据库学习笔记---connect by的简单用法 2019-04-26
数据库学习笔记---SQL基础-->层次化查询(START BY ... CONNECT BY PRIOR) 2019-04-26
编程杂谈---vb,vb.net,java数据类型区分 2019-04-26
项目管理---SVN,Subversion的安装,客户端和服务端 2019-04-26
php学习笔记---PHP生成二维码名片,并把名片内容添加到联系人中 2019-04-26
php学习笔记---php调试和开发工具整理 2019-04-26
Ui学习笔记---EasyUI的介绍 2019-04-26