文章目录
First point :finally和return的小细节回顾
在 finally 代码块中改变返回值并不会改变最后返回的内容。且它一定会被执行!
总结为以下几条:
- 1、当 try 代码块和 catch 代码块中
有 return 语句时,finally 仍然会被执行。
- 2、执行 try 代码块或 catch 代码块中的
return 语句之前,都会先执行 finally 语句。
- 3、无论在 finally 代码块中是否修改返回值,返回值都不会改变,
仍然是执行 finally 代码块之前的值。finally 代码块中的 return 语句一定会执行。
- 4、当 finally 有返回值时,会直接返回该值,不会去返回 try 代码块或者 catch 代码块中的返回值。
注意:finally 代码块中最好不要包含 return 语句,否则程序会提前退出。
例子
1、
第一点
:当 try 代码块或者 catch 代码块中有 return 语句时,finally 仍然会被执行。
第二点
:执行 try 代码块或 catch 代码块中的 return 语句之前,都会先执行 finally 语句。
public class FinallyAndReturnAndThrow {
public static void main(String[]args){
System.out.println(test1());
System.out.println(test2());
}
private static int test1() {//try带return
try{
return 1;
}finally {
System.out.println("finally1");
}
}
private static int test2() {//try和catch都有return
try{
System.out.println("haha"+1/0);
return 4;
}catch(Exception e){
return 2;
}finally {
System.out.println("finally2");
}
}
}
先打印finally,才打印返回值。也就是return是最后执行的!
2、
第四点
:当 finally 有返回值时,会直接返回该值,不会去返回 try 代码块或者 catch 代码块中的返回值。
注意:finally 代码块中最好不要包含 return 语句,否则程序会提前退出。
private static int test3() {//当finally中有返回值则直接返回,不再去执行try或者catch的return
try{
System.out.println("try语句");
return 1;
}catch(Exception e){
return 2;
}finally {
System.out.println("finally4");
return 3;
}
}
先执行try中的代码,在return语句之前先执行finally
,而finally中直接返回return 3;此时finally执行完不会去执行try或者catch中的return;
3、
第三点
:无论在 finally 代码块中是否修改返回值,返回值都不会改变
,仍然是执行 finally 代码块之前的值。finally 代码块中的 return 语句一定会执行。
private static int test4() {
int result=0;
try{
System.out.println("try语句"+1/result);//抛出异常
return result;
}catch(Exception e){//捕抓
return result+1;
}finally {
System.out.println("finally3");
result=100;
System.out.println(result);//打印100后就会去执行try的return
}
}
虽然finally中修改了result的值,但是执行try中的return result是之前的result值 1。
我猜想是利用了弹栈的效果来实现。
所以当 try 代码块或 catch 代码块中的 return 返回值类型为普通变量或引用变量时,即使在后面 finally 代码块中对返回值的变量重新赋值,也不会影响最后返回的值。
One question——finally块中使用return会抑制异常的冒泡传输
代码一:
package 面试题;
/**
* finally块中使用return会抑制异常的冒泡传输
*/
public class FinallyReturnAndThrow2 {
public static void main(String[]args){
div();
}
private static void div() {
try{
System.out.println(1/0);
}catch (Exception e){
System.out.println("div's catch");
throw e;
}finally {
System.out.println("div's finally");
}
}
}
这段代码会抛出异常(除数为0)
现在使用一个方法去调用div()
package 面试题;
/**
* finally块中使用return会抑制异常的冒泡传输
*/
public class FinallyReturnAndThrow2 {
public static void main(String[]args){
displayTest();
}
private static void displayTest() {
try{
div();//调用上面的div方法
}catch (Exception e){
System.out.println("displayTest's catch");
}finally {
System.out.println("displayTest's finally");
}
}
private static void div() {
try{
System.out.println(1/0);
}catch (Exception e){
System.out.println("div's catch");
throw e;
}finally {
System.out.println("div's finally");
}
}
}
结果很正常,成功处理了div中抛出的异常
现在在div()中的finally中添加了return 2;
private static int div() {
try{
System.out.println(1/0);
}catch (Exception e){
System.out.println("div's catch");
throw e;
}finally {
System.out.println("div's finally");
return 2;
}
}
再次运行:
package 面试题;
/**
* finally块中使用return会抑制异常的冒泡传输
*/
public class FinallyReturnAndThrow2 {
public static void main(String[]args){
displayTest();
}
private static void displayTest() {
try{
div();
}catch (Exception e){
System.out.println("displayTest's catch");
}finally {
System.out.println("displayTest's finally");
}
}
private static int div() {
try{
System.out.println(1/0);
}catch (Exception e){
System.out.println("div's catch");
throw e;
}finally {
System.out.println("div's finally");
return 2;//添加了返回值
}
}
}
发现没有catch到异常!即:finally块中的return语句会阻止异常的栈调用传输,使调用者(displayTest)认为该方法已经正常返回
Second point:finally中可能抛出的异常如何处理?
先来看一段代码:
package Stream_IntOut;
import java.io.*;
/**
* 使用缓冲区输入流和缓冲区输出流实现复制文件的功能。
* 并简单处理IO异常
*
*/
public class Practice3_BufferedWriter_BufferedReader_Copy {
public static void main(String[]args){
FileWriter fw = null;
FileReader fr = null;
BufferedWriter bufw = null;
BufferedReader bufr = null;
try{
fw = new FileWriter("E:\\file_copy2.txt");
fr = new FileReader("E:\\file.txt");
bufw = new BufferedWriter(fw);
bufr = new BufferedReader(fr);
String line;
while((line=bufr.readLine())!=null){
bufw.write(line);
//写入换行符
bufw.newLine();
//刷新一次流对象
bufw.flush();
}
}catch(IOException e){
e.printStackTrace();
}finally {
if(fr!=null)
try{
assert bufr != null;
bufr.close();
}catch (IOException e){
throw new RuntimeException("无法关闭fr流对象");
}
if(fw!=null)
try{
assert bufw != null;
bufw.close();
}catch (IOException e){
throw new RuntimeException("无法关闭fw流对象");
}
}
}
}
我们可以从IDEA的提示里边看到一些东西:
finally块里边抛出异常是不建议的,java异常语句中的finally块通常用来做资源释放操作,如关闭文件、关闭网络连接、关闭数据库连接等;finally块和普通代码块一样,无法同时使用return语句和throw语句,因为无法通过编译
正常情况下finally语句中不应该使用return语句,也不应该抛出异常!
首先我们先明确为什么不被建议?——finally块中的throw语句会覆盖try和catch语句中的异常
先来看一个实例代码:
package 面试题;
public class FinallyAndReturnAndThrow3 {
public static void main(String[]args){
displayTest();
}
private static void displayTest() {
try{
System.out.println(2/0);//异常发生
}catch (Exception e){
System.out.println("displayTest's catch");
throw new RuntimeException("除数为0");
}finally {
System.out.println("displayTest's finally");
throw new RuntimeException("俺会覆盖catch的异常");
}
}
}
catch的异常并没有被抛出。同样的try中捕抓的异常也会被掩盖。
回到上面的问题,我们使用IO流时,常常在finally使用到throw,那该如何解决呢?
以下是目前我所知道的:(待了解深入再跟进。)
第一点:可以将抛出的异常写到日志中去,在catch语句块中写入。
第二点:对于可能空的变量操作,我们一定要去做if判断之后再进行响应的操作;
第三点:在Java核心技术书中,作者建议在finally块中尽量不要使用会抛出异常的资源回收语句。
也就是这里的close操作尽量不要出现异常
所以我在上面的代码中加了很多判断null的操作。