Java.try catch finally 的执行顺序说明

示例1:

public static String hello() {
    String s = "商务";
    try {
      return s;
    } catch (Exception e) {
      return "catch进来了";
    } finally {
      s = "你好世界";
      return s;
    }
  }

返回结果:你好世界,此时的返回顺序是 finally > try

示例2:

public static String hello() {
    String s = "商务";
    try {
      return s;
    } catch (Exception e) {
      return "catch进来了";
    } finally {
      s = "你好世界";
    }
  }

返回结果:商务

因为在 try 处会进行 s 值的缓存

示例3:

public static void hehe() {
    int a = 10;
    try {
      a += 1;
      System.out.println(a);
      throw new Exception("catch测试");
    } catch (Exception e) {
      e.printStackTrace();
      a += 10;
      System.out.println(a);
    } finally {
      a += 10000;
      System.out.println(a);
    }
    System.out.println(a);
  }

返回结果:

11
21
10021
10021

故意在 try 处抛出一个异常进入 catch,此时返回的顺序是 try > catch > finally > 最后一行代码

补充知识:Java异常获取中try-catch-finally块执行顺序

最近看面试题,发现这个比较好玩,try-catch-finally块的执行顺序问题。

一般认为,finally最后执行,做收尾工作,无论try块是否捕获异常,最后finally都会工作。但是这样还是比较笼统,如果没有catch,而是将异常抛出,让其他方法处理,那么是先进入其他方法还是先执行finally?如果try块中return了,那么finally还执行不执行?进一步,如果try、finally全部有return,那么执行是怎样的过程?

确实,异常这些还是最早学Java的时候学的,当时似乎也没考虑这么多。借此机会研究一下异常获取的顺序。

节省时间,直接结论:

try->catch->finally按顺序执行,不管是否有异常,不管try中有什么操作,就算是return,也得往后稍稍,最后这个方法一定是要执行finally。

如果try中抛出异常,而异常是留给上层方法处理,那么在抛出后,仍然运行finally,然后再回溯到上层。

自然,如果try中有return——也算是回溯了,返回值会存在栈中等待,等finally运行之后再回溯。

而如果finally中有return,那么直接从finally中结束方法。

如果在方法中直接结束程序,即调用System.exit()方法,那么就直接结束了,此时finally是不执行的。由此可以认为,特殊情况导致程序的退出是可能导致一些问题的。毕竟finally一般写的是关闭对象、资源的代码。

通过代码分析:

先写了一个包含情况比较多的例子:

package me.iwts;
public class Main{
  public static int rank;

  public static void solve1() throws Exception{
    try {
      System.out.println("solve 1 try,rank: "+rank++);
      throw new Exception("throw by solve 1");
    }finally {
      System.out.println("solve 1 finally,rank: "+rank++);
    }
  }

  public static void solve2(){
    try{
      System.out.println("solve 2 try,rank: "+rank++);
      solve1();
    }catch (Exception ex){
      System.out.println("catch exception : "+ex.getMessage()+",rank: "+rank++);
    }finally {
      System.out.println("solve 1 finally,rank: "+rank++);
    }
  }

  public static void main(String args[]) {
    rank = 1;
    solve2();
    System.out.println("over");
  }
}

rank是计数。可以看到,整体上是先调用solve2方法,在其中调用solve1,solve1抛出了一个异常,让solve2捕获处理。大家可以先自己猜一下。

下面是返回答案:

solve 2 try,rank: 1
solve 1 try,rank: 2
solve 1 finally,rank: 3
catch exception : throw by solve 1,rank: 4
solve 1 finally,rank: 5
over

根据上面的结果可以分析:try-catch-finally执行顺序:首先是try执行,如果发生异常,那么直接捕获异常,最后执行finally。但是,如果抛出异常,例如在solve1方法中,throw了一个异常,那么不会立刻回溯到上一个方法,而是仍然执行finally。

通过solve1的执行,我们可以认为,finally之前的所有代码,正常执行,但是返回之类的,全部被“卡”了下来,只有在finally执行之后,才能继续执行。

这里就又有疑惑了,一般认为throw了一个异常,就算是回溯了,为什么finally仍然执行了?如果这个不够明显,那么再看这个代码:

package me.iwts;
public class Main{
  public static int solve(){
    try{
      System.out.println("try");
      return 1;
    }finally {
      System.out.println("finally");
      return 2;
    }
  }

  public static void main(String args[]) {
    System.out.println(solve());
  }
}

返回值是多少?

try
finally
2

try块都已经return了,最后为什么是返回的return2?并且try块确实是运行了。再改一下代码:

package me.iwts;
public class Main{
  public static int solve(){
    int i = 1;
    try{
      System.out.println("try");
      return i++;
    }finally {
      System.out.println("finally");
      return i;
    }
  }

  public static void main(String args[]) {
    System.out.println(solve());
  }
}

注意,try块返回了i++,那么我们debug就能看出来return这句到底是执行还是没执行,那么有这样的图:

可以看到,return确实是执行的。

所以,认为finally是无论怎样一定在方法的最后结束前执行的。搜了一些资料,是说finally会在方法结束之前执行,而之前所有的执行,包括return,全部都停留在栈中,而finally最终执行后才继续。所以这样也能解释,第一次代码本应该回溯的代码执行完finally后才回溯,return的时候也是等finally执行之后再执行。

或许“return的时候也是等finally执行之后再执行”这句话又引出了一个问题:finally究竟是直接运行完结束,还是运行完之后再回到原来return的地方?

这里我们可以把i++换成++i,结果就不截图了——finally就是最终执行,如果有return,直接从finally返回。

还有一种情况,直接结束程序会怎么样?

package me.iwts;
public class Main{
  public static void solve(){
    try{
      System.out.println("try");
      System.exit(0);
    }finally {
      System.out.println("finally");
    }
  }

  public static void main(String args[]) {
    solve();
  }
}

结果:

try

强制结束大过天。由此,也可以认为特殊情况导致程序直接结束,不会执行finally。因为finally一般写的都是关闭对象、资源的代码,所以这些特殊情况导致的程序强制结束,可能会引发一些问题的。

以上这篇Java.try catch finally 的执行顺序说明就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 浅谈java中异常抛出后代码是否会继续执行

    问题 今天遇到一个问题,在下面的代码中,当抛出运行时异常后,后面的代码还会执行吗,是否需要在异常后面加上return语句呢? public void add(int index, E element){ if(size >= elements.length) { throw new RuntimeException("顺序表已满,无法添加"); //return; //需要吗? } .... } 为了回答这个问题,我编写了几段代码测试了一下,结果如下: //代码1 public

  • 对python中的try、except、finally 执行顺序详解

    如下所示: def test1(): try: print('to do stuff') raise Exception('hehe') print('to return in try') return 'try' except Exception: print('process except') print('to return in except') return 'except' finally: print('to return in finally') return 'finally'

  • 深入浅析java中finally的用法

    finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常),经常被用在需要释放资源的情况下. 之前在写爬虫的时候数据库连接的频率很高,有时候数据处理的不好,sql报错后,抛出异常但后边的数据库连接没有断开.导致最后数据库连接数过大,不让再连接了(因为是个人库,所以直接重启了一下).这个释放数据库连接的操作就可以用finally来进行. 首先看一下没有用finally的代码(不能直接运行,能看懂什么意思就行) Co

  • Java.try catch finally 的执行顺序说明

    示例1: public static String hello() { String s = "商务"; try { return s; } catch (Exception e) { return "catch进来了"; } finally { s = "你好世界"; return s; } } 返回结果:你好世界,此时的返回顺序是 finally > try 示例2: public static String hello() { Str

  • 举例说明Java中代码块的执行顺序

    前言     今天在看Android ContentProvider实现的时候,突然想到了Java类在new的过程中,静态域.静态块.非静态域.非静态块.构造函数的执行顺序问题.其实这是一个很经典的问题,非常考察对Java基础知识的掌握程度.很多面试过程中相信也有这样的问题,趁着周末有时间复习一下. 结论     这里先把整理好的结论抛给大家,然后我在写个程序来验证我们的结论.在Java类被new的过程中,执行顺序如下: 实现自身的静态属性和静态代码块.(根据代码出现的顺序决定谁先执行) 实现自

  • try catch finally的执行顺序深入分析

    首先执行try,如果有异常执行catch,无论如何都会执行finally 一个函数中肯定会执行finally中的部分. 关于一个函数的执行过程是,当有return以后,函数就会把这个数据存储在某个位置,然后告诉主函数,我不执行了,接下来你执行吧,所以函数就会推出. 但是当一个函数中出现finally以后,finally永远都要执行,所以,就算try或者catch中已经执行了return了,但是这时函数不会退出,不会告诉主函数去执行,而是等待finally执行完了才回去告诉主函数去执行,这时候如果

  • 在Java中自由块的执行顺序

    java中的自由块分为静态的自由块和非静态的自由块. 非静态自由块的执行时间是:在执行构造函数之前. 静态自由块的执行时间是:class文件加载时执行. 非静态自由块可以多次执行,只要初始化一个对象就会执行,但是静态自由块只会在类装载的时候执行一次,一般用来初始化类的静态变量的值. 每次初始化一个对象,都会导致一次非静态块的执行. 如果涉及到继承,则是:首先执行父类的非静态块,然后是父类的构造函数,接着是自己的自由块,最后是自己的构造函数. 静态块的执行时机是在class文件装载的时候,clas

  • Java拦截器Interceptor和过滤器Filte的执行顺序和区别

    目录 1.实现原理不同 2.使用范围不同 3.触发时机不同 4.拦截的请求范围不同 5.注入Bean情况不同 6.控制执行顺序不同 1.实现原理不同 过滤器和拦截器 底层实现方式大不相同,过滤器 是基于函数回调的,拦截器 则是基于Java的反射机制(动态代理)实现的. 1.拦截器是基于java的反射机制的,而过滤器是基于函数回调 2.过滤器依赖与servlet容器,而拦截器不依赖与servlet容器 3.拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用 4.拦截器可以访问

  • Android代码块执行顺序分析总结

    本文介绍了Android代码块执行顺序分析总结,分享给大家,具体如下: 子类.父类变量,代码块,以及构造方法的加载顺序,是我们在程序开发中时不时遇到的一个问题,也是比较容易混淆的. 基础准备: 变量: 成员变量(叫类变量.实例变量)和局部变量 方法: 成员方法和构造方法 代码块:普通代码块.构造代码块.静态代码块.同步代码块 测试的父类: public class ParentClass { public static String name = "爸爸"; public int ag

  • java异常处理执行顺序详解try catch finally

    目录 不含return的执行顺序 finally子句 含return的执行顺序 返回类型是对象类型时值的变化 结论 不含return的执行顺序 执行顺序为执行try中代码,如果没有异常,然后执行try catch后续的代码.如: public static void main(String[] args) { try { int j = 10 / 2; System.out.println("执行try中代码!"); } catch (Exception e) { e.printSta

  • 关于Java中try finally return语句的执行顺序浅析

    问题分析 finally语句块一定会执行吗? 可能很多人第一反应是肯定要执行的,但仔细一想,如果一定会执行的话 也就不会这么SB的问了. Demo1 public class Test { public static void main(String[] args) { System.out.println("return value of test(): " + test()); } public static int test() { int i = 1; // if (i ==

  • Java实现指定线程执行顺序的三种方式示例

    本文实例讲述了Java实现指定线程执行顺序的三种方式.分享给大家供大家参考,具体如下: 方法一:通过共享对象锁加上可见变量来实现. public class MyService { private volatile int orderNum = 1; public synchronized void methodA() { try { while (orderNum != 1) { wait(); } for (int i = 0; i < 2; i++) { System.out.printl

  • Java中try-catch-finally执行顺序你知道吗

    目录 引言 正文 try块中有return catch块中有return try块和finally块中有return catch块和finally块中有return try块.catch块和finally块中都有return 总结 引言 java异常处理中,try.catch.finally的执行顺序,大家都知道是按顺序执行的,这里我就不废话了.但是当try.catch.finally中加入return之后,就会有几种不同的情况出现,下面分别来说明一下.也可以跳到最后直接看总结. 正文 这里共列

随机推荐