1. try/catch/finally 介绍
try
:用来捕获异常
catch
:用于处理try中捕获的异常
finally
:无论是否捕获或处理异常,finally块中的代码都会被执行。
- try必须有
- finally可以无
总结:
- try后面必须跟catch 或者 finally 其中之一
- try后面可以有0个或者多个catch,只能有0个或者1个finally。
- 若try后面没有catch,则必须有一个finally
2. try/catch/finally 执行顺序
在Java中,try-catch-finally语句块的执行顺序是:
- try块:首先执行try块中的代码。如果有return语句,则会执行并返回。
- finally块:无论try块中是否有return语句,都会执行finally块中的代码。这使得finally块成为一个可靠的清理代码块,它可以在方法返回之前执行任何必要的清理操作,例如关闭打开的资源。
- catch块:如果在try块中抛出了异常,则会跳转到相应的catch块执行。如果在catch块中也有return语句,则会执行并返回。
具体可以分以下情况讨论:
情况1:里面均无return语句
- try里面的代码执行
若try里面捕获了异常,则执行catch语句;否则不执行catch语句; - 1.若有多个catch块,当进入一个catch块,执行完毕后;
2.即使后面还有catch块,也不会再进入其他catch块。(类似if一样选择了一个catch,其他就会跳过)
3.如果有finally块,则进入finally块。 - finally块一定会执行(不论释放出现异常)
情况2:里面加上return语句
- finally中无return:当try块中或者catch块中遇到return语句时,先执行完finally里面的代码后,再执行try 或者 catch中的return语句。
是执行try中的还是catch中的return得看try中是否有异常;
无异常则走try块,有异常则走catch块; - 当finally里面有return语句:
①无异常时,走完try里面的代码,return也会走,然后执行finally里面的代码,最后finally里面的return会覆盖掉try之前return的结果;
②有异常时,走catch里面的代码,同样继续执行了catch里面的return,最后走finally里面的代码,finally里面的rerturn最终会覆盖catch的return;
总结:无论是否异常,finally不会影响try、catch里面的return语句,只是当finally里面的return会最后覆盖掉前面return的结果!!
我们来举例说明:
3. 我们来做道题
最后程序输出 i=?
public int test() {
int i = 0;
try {
i++;
i = i / 0;
return i++;
} catch (Exception e) {
i++;
return i++;
} finally {
return ++i;
}
}
public static void main(String[] args) {
System.out.println(test());
}
大家先别看答案自己想想哦
- 答案:4
为什么是4呢?我前面不是说直接执行finally里面的return语句吗? - 解释:
原来,我们try / catch里面的return语句在程序里面是走了这步的,只不过最后finally块里面的return语句覆盖掉了前面的。
再看一个例子
public static int testAbc() {
int i = 0;
try {
i++;
i = i / 0;
return i++;
} catch (Exception e) {
i++;
return i=7;
} finally {
return ++i;
}
}
//这个输出的结果就是8
原因:
首先,我们分析程序的执行流程:
-
初始化 i 为 0。
-
进入 try 块,i 自增,此时 i = 1。
-
执行 i = i / 0,这会抛出 ArithmeticException(因为除以0是不允许的)。
-
因为有异常抛出,所以程序跳转到 catch 块。
-
在 catch 块中,i 自增,此时 i = 2。
-
然后执行 return i=7,将 i 的值设为 7 并返回。
但是,这里有一个关键点:在 Java 中,finally 块总是会被执行,无论是否有 return 语句在 try 或 catch 块中。因此,即使在 catch 块中已经有一个 return 语句,程序还是会跳转到 finally 块执行。
-
在 finally 块中,执行 return ++i,这将 i 的值自增并返回。由于这是在 finally 块中的返回语句,所以它会覆盖前面的所有返回语句。
因此,这个程序的结果是:8
原因:在 finally 块中,i 的值被自增了1,从7变为8,并且这个返回值覆盖了前面的所有返回值。所以,方法最终返回的是8。
举个例子
public static int testAbc() {
int i = 0;
try {
i++;
System.out.println("我是try");
i = i / 0;
return i++;
} catch (Exception e) {
System.out.println("我是catch");
i++;
return i=7;
} finally {
System.out.println("我是finally");
return ++i;
}
}
结果:
我是try
我是catch
我是finally
i=8
public static int getInt() {
int a = 10;
try {
System.out.println(a / 0);
a = 20;
} catch (ArithmeticException e) {
a = 30;
return a;
/*
* return a 在程序执行到这一步的时候,这里不是return a 而是 return 30;这个返回路径就形成了
* 但是呢,它发现后面还有finally,所以继续执行finally的内容,给a赋值40,但是finally并没有return;
* 所以执行完finally后再次回到以前的路径,继续走return 30,形成返回路径之后,这里的a就不是a变量了,而是常量30
*/
} finally {
a = 40;
}
return a;
}
//输出30
public static int getInt() {
int a = 10;
try {
System.out.println(a / 0);
a = 20;
} catch (ArithmeticException e) {
a = 30;
return a;
} finally {
a = 40;
//如果这样,就又重新形成了一条返回路径,由于只能通过1个return返回,所以这里直接返回40
return a;
}
}
//输出40
4. 最后结论
- finally一定会执行;
- finally一般不要写return,系统认为会是一个warning
- finally里面的return不会影响try、catch里面的return,最后只是覆盖掉前面的return而已;