Java异常finally与方法返回值

本文探讨了Java异常处理中的finally块与方法返回值的关系。即使在catch块中return,finally仍然会执行,但对基本类型的返回值修改无效。Java 7引入的try-with-resources简化了资源关闭。此外,异常链允许封装异常源头,而在有返回值的函数中,finally不应包含return语句。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异常处理常见面试题

1. try-catch-finally 中哪个部分可以省略?

catch和finally可以省略其中一个 ,catch和finally不能同时省略 注意:格式上允许省略catch块, 但是发生异常时就不会捕获异常了,我们在开发中也一般不会这样去编写代码.

单独的try只适合处理运行时异常,try+catch适合处理运行时异常+编译时异常。如果只用try去处理编译时异常却不用catch处理,无法通过编译,必须用catch显示声明以便进一步处理。而运行时异常在编译时 没有如此规定,所以catch可以省略。 finally是不管有没捕获异常,都要进行的“扫尾”处理。

2. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

会执行,在 return 前执行在 finally 中改变返回值的做法是不合理的,因为如果存在 finally 代码块,try,catch中的 return 语句不会立马返回调用者而是记录下返回值的副本,待 finally 代码块执行完毕之后再向调用者返回其值,然后即使在 finally 中 修改了返回值,也不会返回修改后的值(仅适用于trycatch中的返回值,如果没有在try catch中返回,则finally会改变变量的值)显然,在 finally 中返回或者修改返回值会对程序造成很大的困扰,Java中也可以通过提升编译器的语法检查级别来产生警告或错误。因为 return 表示的是 要整个方法体返回, 所以,finally 中的语句会在 return 之前执行。 但是 return 前执行的 finally 块内,对数据的修改效果对于引用类型和值类型会不同(详见下方代码块)

finally中的代码会执行详解: 执行流程:

  1. 先计算返回值, 并将返回值存储起来, 等待返回
  2. 执行finally代码块
  3. 将存储的返回值, 返回出去;

注意:

  • 返回值是在finally运算之前就确定了(基本数据类型),并且缓存(副本)了,不管finally对该值做任何的改变,返回的值都不会改变(不在finally中return)
  •  finally代码中不建议包含return,因为程序会在上述的流程中提前退出,也就是说返回的值不是try或 catch中的值(下方代码块的额第二个例子)
  •  如果在try或catch中停止了JVM,则finally不会执行.例如停电- -, 或通过如下代码退出 JVM:System.exit(0);
  1.  在 finally 语句块第一行发生了异常,除了第一行,finally 块还是会得到执行
  2.  在前面的代码中(包括try或catch中)用了 System.exit(int)已退出程序。 exit 是带参函数 ;但是若该语句在异常语句之后,finally 会执行
  3.  程序所在的线程死亡
  4.  关闭 CPU
 public static int getInt() {
        int a = 10;
        try {
            System.out.println(a / 0);
            a = 20;
        } catch (ArithmeticException e) {
            a = 30;
            return a; /a的副本(30)被保存了起来,
接着执行的finally只是改变a的值,并不改变保存起来的将要返回的副本(30)
            */
            
        } finally {
            a = 40;
        }
        return a;
    }
    public static int getInt1() {
        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;
        }
    }
   // 修改基本类型
    static int f() {
        int ret = 0;
        try {
            return ret; // 返回 0,finally 内的修改效果不起作用
        } finally {
            ret++;
            System.out.println("finally 执行");
        }
    }
    // 修改引用类型
    static int[] f2(){
        int[] ret = new int[]{0};
        try {
            return ret; // 返回 [1],因为备份(副本)是数组的地址值,finally 内的修改效果起了作用
        } finally {
            ret[0]++;
            System.out.println("finally 执行");
        }
    }

try-with-resources

对于文件操作 IO 流、数据库连接等开销大的资源,用完之后必须及时通过 close 方法将其关闭,否则资源会一直处于打开状态,可能会导致内存泄露等问题。 关闭资源的常用方式就是在 finally 块里是释放,即调用 close 方法。

public static void main(String[] args) {
    BufferedReader br = null;
    try {
        String line;
        br = new BufferedReader(new FileReader("d:\\hollischuang.xml"));
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
     } catch (IOException e) {
        // handle exception
     } finally {
        try {
            if (br != null) {
                br.close();
            }
        } catch (IOException ex) {
            // handle exception
        }
     }
}

从 Java 7 开始,jdk 提供了一种更好的方式关闭资源,使用 try-with-resources 语 句,改写一下上面的代码,效果如下:

public static void main(String... args) {
    try (BufferedReader br = new BufferedReader(new FileReader("d:\\ hollischu
        ang.xml"))) {
        String line;
        while ((line = br.readLine()) != null) {
               System.out.println(line);
        }
    } catch (IOException e) {
        // handle exception
    }
}

背后的原理也很简单,没有做的关闭资源的操作,编译器都做了。 所以语法糖的作用就是方便程序员的使用,但最终还是要转成编译器认识的语言(就像泛型)。

异常链

“异常链”是 Java 中流行的异常处理概念, 是指在进行⼀个异常处理时抛出了 另外⼀个异常, 由此产生了⼀个异常链条。 该技术多用于将“ 受检查异常” ( checked exception) 封装成为“非受检查 异常”( unchecked exception)( RuntimeException)。如果在处理异常时抛出⼀个新的异常,则⼀定要包含原有的异常, 这样, 处理程序才可以通过 getCause()和 initCause()⽅法来访问异常最终的根源。

try {
} catch (IOException e) {
    throw new SampleException("Other IOException", e);
}

当捕获到 IOException 时,将创建一个新的 SampleException 异常, 并附加原始的异常原因,并将异常链抛出到下一个更高级别的异常处理程序。

关于代码块中有try catch的函数的返回值

如果函数没有返回值,则在try catch中都必须有返回值,否则编译失败。如果在try catch都没有返回值,则必须在finally中返回(不建议)

如果函数有返回值,则在 finally中不能有返回值(unreachable),在try或catch中可以有返回值(只能有一个,二选一)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值