finally与return纠缠不清

2024-02-01 11:12
文章标签 return finally 纠缠不清

本文主要是介绍finally与return纠缠不清,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

finally与return纠缠不清

在常规认知中我们都知道finally关键字的作用是为了无论程序是否抛出异常都需要执行的代码声明,但是在搭配return使用时就开始逐渐模糊,逐步拉扯,逐渐抓狂。

前言

我们都知道finally中的代码是在return之后执行的,那么在return语句中对最终返回的结果进行了逻辑处理,finally中的代码还会生效吗?我们看如下代码:

public static int finallyTest(int x){try{return x+2;}finally {x++;}
}

如果我们传入x=1,那么最终返回的结果是多少呢?是3?是2?还是1?

同样的还有如下类似代码:

public static String getString(){String str = "abc";try{str += "def";return str;}catch (Exception e){e.printStackTrace();}finally {str += "ghi";str = null;}return str;
}

返回的字符串是多少呢?是abcdef?是abcghi?是abcdefghi?还是null?

以上两段代码看起来非常简单,可能大部分人不会混淆;但是不能完全理解的话在实际开发中由于方法之间代码量较大很容易就陷入其中,导致最终很难排查的系统BUG。

场景罗列

我们先罗列一下finally与return在使用过程中的使用场景,方便我们有一个系统认识

1、正常情况下try中包含return,finally中无return

如前言中包含的两种场景,对于第一种场景返回的x=3;对于第二种场景返回的str=“abcdef”

2、正常情况下try中包含return,finally中有return

将之前例子中finally中添加return关键字

public static String getString(){String str = "abc";try{str += "def";return str;}catch (Exception e){e.printStackTrace();}finally {str += "ghi";return str;}
}

此时finally中的return就会覆盖try中的return,返回值变成了"abcdefghi"

3、发生异常时catch中包含return
public static String getString(){String str = "abc";try{str += "def";if(str.length() >0 )throw new Exception("发生了异常");return str;}catch (Exception e){e.printStackTrace();return str;}finally {str += "ghi";str = null;}
}

此时retrun效果等同于try中的return,返回值为"abcdef"

4、发生异常时catch中无return
public static String getString(){String str = "abc";try{str += "def";if(str.length() >0 )throw new Exception("发生了异常");return str;}catch (Exception e){e.printStackTrace();}finally {str += "ghi";}return str;
}

此时返回值变成了"abcdefghi"

通过执行上边各场景的代码会发现只要return不在finally中,那么写在finally中的代码其实是无效的;这与我们的认知就出现了偏差,为什么会出现这样的现象?

我们将操作的对象换成Map再来测试一下:

5、以上四个场景使用Map进行验证
public static Map<String,String> getMap(){Map<String,String> map = new HashMap<>();map.put("KEY","INIT");try{map.put("KEY","try");if(map.size() > 0)throw new Exception("发生了异常");return map;}catch (Exception e){e.printStackTrace();map.put("KEY","catch");}finally {map.put("KEY","finally");map = null;}return map;
}

我们得到了如下结果:

1、正常情况下try中包含return,finally中无return  ----{KEY,finally}
2、正常情况下try中包含return,finally中有return  ----null
3、发生异常时catch中包含return                  ----{KEY,finally}
4、发生异常时catch中无return                    ----null

针对Map的测试我们看到了和我们预期相符的输出结果。

问题出现

1、为什么对于不同的数据类型会出现不同的情况?

针对基本数据类型在finally中对其进行修改是无效的,而引用数据类型修改可以生效;但是String类型是一个特例,因为String不是基本数据类型但是修改也是无效的。

2、finally中对于对象赋值null的操作为什么有些场景生效,而有些场景不生效?

null对象是一个特殊的对象,为对象赋值null代表了该对象不再存在。结合问题1会发现,在finally中对对象的更改不会生效,而对对象引用的修改则会生效。

总结

我们首先要知道return关键字的含义,其用于跳出当前方法,指向返回值指针(指针、指针、指针 …),即返回对象的内存地址。因此finally的操作能够更改的仅仅是该内存地址所存储的对象值,而不能更改该内存地址。

函数返回的步骤:
  • 先记录return指针位置,即此时返回值指针位置。
  • 然后执行finally语句块,
  • 然后返回return的指针位置。(至此函数执行结束)
  • 所以return指针位置已固定,是不可改变的事实,一切能改变return指针位置所指向的内容的行为均可改变返回值。而所有想要改变指针位置的操作均是无效的。

这样就可以解释基本数据类型每次修改均会导致内存地址的变更,因此在finally中的修改是不生效的;而String是一个特殊的引用数据类型,其存在在常量池中,对String对象执行“+=”操作相当于新创建一个String对象并将原String对象复制给新的String对象,这个时候也涉及到了内存地址的变更,因此也是不会生效的;对Map对象的修改则仅是内存地址中值的变动,不涉及到内存地址变更,因此修改是生效的。如果将Map对象直接赋值null的操作则会导致内存地址的变动,此操作不会生效。

特别注意

在上边测试中为了展示不同场景,在finally中添加了return;但是在实际开发中严禁在finally中添加return关键字,这样的操作可能会导致程序出现异常时无法反馈到日志中,进而出现无法捕获的异常。

这篇关于finally与return纠缠不清的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/667100

相关文章

try -catch-finally的理解,同时在try-catch-finally中含有return和throws的理解

在没有try-catch或try-catch-finally的情况下,程序正常执行到某行,在这行报错后,这行后面的代码就不执行了,程序就停止了,中断了。 例如   在有try-catch或try-catch-finally 情况上,在某行执行错误,在try中这行下的代码不执行,try外的代码执行。当然是catch在没有做处理的情况下。如果catch中做了处理,在不影响当前程序下,try

王立平--AES加密图片实现 SkImageDecoder::Factory return null

这个问题是在加密图片,存入sd卡,在解密出来展示,出现的。我个人研究了很久没解决。最后经过高人指点,终于解决了。 在此,拿出来分享,希望各位少走弯路。 我之前的设计思路是:(可以不看哦) 1.把图片从drawable读入成bitmap 2.bitmap-->byte 3.调用AES的byte加密算法。 4.加密成byte,在转化为string 5,把string存入sd卡。

Java中finally关键字的使用

与其他语言的模型相比,finally 关键字是对 Java 异常处理模型的最佳补充。finally 结构使代码总会执行,而不管有无异常发生。使用 finally 可以维护对象的内部状态,并可以清理非内存资源。 如果没有 finally,您的代码就会很费解。例如,下面的代码说明,在不使用 finally 的情况下您必须如何编写代码来释放非内存资源: import java.net.*; impo

VS2013 + QT5.7.0静态编译 错误 .NMAKE:fatal error U1077. return code 0x2,使用 类 模板 需要 模板 参数列表

最近准备搞下QT,早有耳闻,QT的动态库机制让QT的程序大的无比,这我肯定是不能容忍的,准备使用静态库的方式,那就编译源码吧! 下面我说下环境以及碰到的问题 文章参考了http://blog.csdn.net/u011964923/article/details/52886908 ,但是我的报错了。。。下面是解决. 1.环境问题 1.QT版本 :qt5.7  qt-op

C++异常处理: try,catch,throw,finally的用法

写在前面 所谓异常处理,即让一个程序运行时遇到自己无法处理的错误时抛出一个异常,希望调用者可以发现处理问题. 异常处理的基本思想是简化程序的错误代码,为程序键壮性提供一个标准检测机制. 也许我们已经使用过异常,但是你习惯使用异常了吗? 现在很多软件都是n*365*24小时运行,软件的健壮性至关重要.  内容导读本文包括2个大的异常实现概念:C++的标准异常和SEH异常. C++标

[置顶]C++异常处理:try,catch,throw,finally的用法

写在前面 所谓异常处理,即让一个程序运行时遇到自己无法处理的错误时抛出一个异常,希望调用者可以发现处理问题. 异常处理的基本思想是简化程序的错误代码,为程序键壮性提供一个标准检测机制. 也许我们已经使用过异常,但是你习惯使用异常了吗? 现在很多软件都是n*365*24小时运行,软件的健壮性至关重要.  内容导读本文包括2个大的异常实现概念:C++的标准异常和SEH异常. C++标

【C++】win7 64下VC++6.0(Unable to register this add-in because its DLLRegisterServer return an error)

 FileTool.exe用于替换 Visual C++ 使用开发人员 Studio 对象模型中的打开和添加到项目菜单项。也是一个修复 VC6.0打开文件时出错退出的插件。 1. 下载FileTool.exe,并解压 2. 打开VC6.0,点击File-Open Workspace,选择刚解压出来的FileTool.dsw,并确定 3. 点击Bulid-Build FileTool.

try-catch-finally中finally的使用

1.finally时可选的 2.finally中声明的时一定会被执行的代码,即使catch中又出现异常了,try中有return语句,catch中有return语句的情况 3.像数据库连接,输入输出流,网络编程Socket等资源,JVM时不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。

c++ 解释return {it->second,i}; 这条语句中每个单词的含义

在 C++ 中,return {it->second, i}; 语句的含义可以分解为以下几个部分。 1. return 含义:return 是一个关键字,用于从一个函数中返回值。在函数执行到 return 语句时,会结束函数的执行,并将后面跟随的值返回给调用该函数的地方。 2. {it->second, i} 含义:这个部分使用了列表初始化(C++11 及以后版本引入的特性)。它表示创建一

try里面放return,finally还会执行吗?

引言 喜欢请点赞,支持点在看。 关注牛马圈,干货不间断。 趣聊 今天,在与同事讨论编程语言特性时,我们谈到了一个有趣的话题:在JavaScript中,finally块中的return语句是否会覆盖try块中的return。我首先通过网络搜索,发现关于这一问题的讨论颇多,其中一篇关于JavaScript的文章尤为引人关注。以下是该文章的部分内容截图: ❝ 文章指出,在JavaScript中