我的一位朋友前阵子遇到一个问题,问题的核心就是try……catch……finally中catch和finally代码块到底哪个先执。这个问题看起来很简单,当然是“catch先执行、finally后执行”了?真的是这样吗?

有下面一段C#代码,请问这段代码的执行结果是什么?

public static void Main(string[] args)

{

      try

      {

            A();

      }

      catch

      {

            Console.WriteLine("catch!!!");

      }

}

static void A()

{

      try

      {

            throw new Exception();

      }

      finally

      {

             Console.WriteLine("finally!!!");

      }

}

A()方法的try代码块中抛出了异常,而A方法没有处理这个异常,所以Main方法的catch代码块会捕获这个异常,但是A()方法中又有finally代码块,那么到底是异常抛出后先执行Main方法的catch代码块呢还是先执行A()方法中的finally代码块呢?运行一下程序就能看出来,是finally代码块执行,结果如下所示。

finally!!!

catch!!!

为什么呢?这需要从方法调用的异常对象如何传递给被调用方法讲起。在一段代码调用一个方法的时候,被调用的方法会把返回值、异常对象等放到一个特定的位置,这个位置叫做Stack Frame,调用者代码会从这个特定的位置获得被调用方法的返回值、异常对象等信息。因此,无论是throw异常的时候还是return返回值的时候,被调用的方法只是把异常对象或者返回值放到了这个特定的位置,在return或者throw执行之后,如果方法中还有finally等没有执行完成的代码,那么这些代码仍然会在return、throw之后继续执行,然后方法执行才会结束,之后调用这个方法的代码才会从Stack Frame中读取到返回值或者获取到被调用的方法抛出的异常对象。因此,上面的代码才会先执行finally然后才执行catch。

明白了这个道理,请回答一下,下面代码的执行结果是什么?

public static void Main(string[] args)

{

      try

{

A();

}

catch(Exception ex)

{

Console.WriteLine(ex.Message);

}

}

static void A()

{

      try

      {

            throw new Exception("aa");

      }

      finally

      {

            throw new Exception("bb");

      }

}

上面这是一段很特殊的代码,在try代码块中抛出了一个异常(信息是aa),在finally中也抛出了一个异常(信息是bb),那么程序实际打印出来的异常信息是什么呢?上面程序执行结果是“bb”。通过上面的分析不难理解其原理:try代码块中的throw new Exception("aa")把方法的异常对象设置为Exception("aa"),而finall代码块中的throw new Exception("bb")又把方法的异常对象修改为Exception("bb"),因此最终方法抛出的异常对象是Exception("bb")。

接下来,我们再来捉弄一下方法的返回值,我们尝试在finally代码块中修改方法的返回值。不幸的是(也可以说,幸运的是),C#禁止我们在finally代码块使用return语句,不过我们可以在Java中做这样的尝试,如下Java代码所示:

public static void main(String[] args)

{

      System.out.println(A());

}

static int A()

{

      try

      {

            return 1;

      }

      finally

      {

            return 2;

      }

}

我们在try代码块中通过return 1把方法的返回值设置为1,但是在finally代码块中又把方法的返回值设置为2,因此方法的最终返回值就是2。

综上所述,一个方法中通过return设定返回值或者throw抛出异常的时候,方法并没有立即返回,只是在Stack Frame上保存了这个返回值或者异常对象,然后会继续执行finally中的代码,如果我们在finally代码块中修改了返回值或者抛出了新的异常,那么最终的调用中获得的返回值或者捕获的对象就是修改后的返回值或者异常对象。

你真的知道吗?catch、finally和return哪个先执行的更多相关文章

  1. try,catch,finally含return时的执行顺序及丢失的伪例

    最近面试遇到一个之前也看到过但没去看一下的问题.就是有return情况下的try,catch,finally的执行顺序. 今天写了下. 先看顺序问题.总结如下: 一:finally中没有写return ...

  2. 再问你一遍,你真的了解try..catch(finally)吗???

    定义 首先来看下 MDN 的定义: The try...catch statement marks a block of statements to try and specifies a respo ...

  3. try--catch--finally中return返回值执行的顺序(区别)

    1.try块中没有抛出异常,try.catch和finally块中都有return语句 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static int ...

  4. try--catch--finally中return返回值执行的顺序

    1.try块中没有抛出异常,try.catch和finally块中都有return语句 public static int NoException(){ int i=10; try{ System.o ...

  5. Java finally语句是在try或catch的retrurn之前还是之后执行

    若try或catch中没有return语句,则按正常执行流,从上到下,finally里的所有修改都生效. 这里讨论的是try或catch里有return或throw语句的情形,此情形比较让人迷惑. 总 ...

  6. Java中try catch finally语句中含return语句的执行情况总结-编程陷阱

    前言:有java编程基础的人对java的异常处理机制都会有一定了解,而且可能感觉使用起来也比较简单,但如果在try catch finally语句块中遇到return语句,开发者可能就会遇到一些逻辑问 ...

  7. 【转】Java中try catch finally语句中含有return语句的执行情况(总结版)

    Java中try catch finally语句中含有return语句的执行情况(总结版) 有一点可以肯定,finally块中的内容会先于try中的return语句执行,如果finall语句块中也有r ...

  8. java中 try catch finally和return联合使用时,代码执行顺序的小细节

    代码1测试 public static void main(String[] args) { aa(); } static int aa() { try { int a=4/0; } catch (E ...

  9. try、catch、finally都有return语句时执行哪个

    任何执行try 或者catch中的return语句之前,都会先执行finally语句,如果finally存在的话.如果finally中有return语句,那么程序就return了,所以finally中 ...

  10. Java_try,catch,finally return之间的执行顺序

    以往认为函数只要执行到return语句便会返回结果并终止,然而这时错误的,因为这存在特例. 掌握下面几条原则就可以完全解决“当try.catch.finally遭遇return”的问题. 原则:1.f ...

随机推荐

  1. 【Azure 媒体服务】Media Service的编码示例 -- 创建缩略图子画面的.NET代码调试问题

    问题描述 在中国区Azure上,使用Media Service服务,想要使用.NET的代码来对上传视频创建缩略图(Thumbnail) . 通过官网文档(https://docs.azure.cn/z ...

  2. 2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库。请用go语言将yuv文件编码为h264文件。

    2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库.请用go语言将yuv文件编码为h264文件. 答案2023-02-28: 使用 ...

  3. 2022-03-23:在k进制下,最小多小的num,可以让1~num范围的数拥有1的个数不少于n个? 腾讯音乐2022校园招聘。

    2022-03-23:在k进制下,最小多小的num,可以让1~num范围的数拥有1的个数不少于n个? 腾讯音乐2022校园招聘. 答案2022-03-23: 二分法. 代码用golang编写.代码如下 ...

  4. Selenium - 元素定位(1) - 八种元素定位

    Selenium - 元素定位 八种元素定位 我们在做WEB自动化时,最根本的就是操作页面上的各种元素,而操作的基础便是元素的定位,只有准确地定位到唯一元素才能进行后续的自动化控制,下面将对各种元素定 ...

  5. 【一步步开发AI运动小程序】二、引入插件

    随着人工智能技术的不断发展,阿里体育等IT大厂,推出的"乐动力"."天天跳绳"AI运动APP,让云上运动会.线上运动会.健身打卡.AI体育指导等概念空前火热.那 ...

  6. 2023-05-24:为什么要使用Redis做缓存?

    2023-05-24:为什么要使用Redis做缓存? 答案2023-05-24: 缓存的好处 买啤酒和喝啤酒的例子可以帮助我们理解缓存的好处. 假设你在超市里买了一箱啤酒,如果你需要每次想喝啤酒就去超 ...

  7. (亲测有效-专门解决Mac环境)Pycharm 解决无法打开的问题

    前提是Mac 安装了PyCharm.app 1.第一步:先输入: cd /Applications/PyCharm.app/Contents/MacOS 2.第二步:查看无法打开pycharm的原因, ...

  8. 【LeetCode双向链表】LRU详解,双向链表实战

    LRU缓存 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构. 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity ...

  9. Intellij IDEA最新激活码,适合2022,2023和所有版本,永久更新

    分享一下 IntelliJ IDEA 2023.1 最新激活注册码,破解教程如下,可免费永久激活,亲测有效,下面是详细文档哦~ 申明:本教程 IntelliJ IDEA 破解补丁.激活码均收集于网络, ...

  10. Pinot2的开发者社区和教程

    目录 文章背景: Pinot 2 是任天堂公司于2018年发布的一款游戏机,采用了基于马里奥兄弟游戏<塞尔达传说:荒野之息>的开放世界操作系统,并推出了许多创新的功能,例如"超级 ...