在学习过程中发现了这样一段注释
/*** 实现了 AutoCloseable 接⼝的类,在 try() ⾥声明该类实例的时候,在 try 结束后⾃动调⽤的 close ⽅法,这个动作会早于* finally ⾥调⽤的⽅法,不管是否出现异常,try() ⾥的实例都会被调⽤ close ⽅法* 在 try ⾥⾯可以声明多个⾃动关闭的对象,越早声明的对象,会越晚被 close 掉*/ try (ServletOutputStream outputStream = response.getOutputStream()){ImageIO.write(bufferedImage, "jpg", outputStream);outputStream.flush(); } catch (IOException e) {log.error("验证码模块-获取图形验证码异常:{}", e); }
那么问题来了-- AutoCloseable 接⼝的类,在 try() ⾥声明该类实例的时候,在 try 结束后⾃动调⽤的 close ⽅法。这个动作是如何实现的呢?
答案:
当一个类实现了 AutoCloseable 接口时,Java的try-with-resources语法会自动在try块结束后调用其 close() 方法。这是Java语言的内置特性。
工作原理:
1. 编译器处理:编译器会自动为try-with-resources语句生成相应的字节码
2. 自动调用:在try块正常结束或异常退出时,JVM会自动调用资源的 close() 方法
3. 异常处理:即使在关闭资源时发生异常,也会被正确处理
try-with-resources代码写法:
/*** 实现了 AutoCloseable 接⼝的类,在 try() ⾥声明该类实例的时候,在 try 结束后⾃动调⽤的 close ⽅法,这个动作会早于* finally ⾥调⽤的⽅法,不管是否出现异常,try() ⾥的实例都会被调⽤ close ⽅法* 在 try ⾥⾯可以声明多个⾃动关闭的对象,越早声明的对象,会越晚被 close 掉*/
// try-with-resources - 自动关闭资源 try (ServletOutputStream outputStream = response.getOutputStream()){
// 使用资源ImageIO.write(bufferedImage, "jpg", outputStream);outputStream.flush(); }//自动调用 outputStream.close()catch (IOException e) {log.error("验证码模块-获取图形验证码异常:{}", e); }
调用时机:
正常执行:try块执行完毕后自动调用
异常情况:即使在try块中抛出异常,也会确保调用 close() 方法
多个资源:按照声明的相反顺序依次关闭
try-catch-finally 写法:
ServletOutputStream outputStream = null;try {outputStream = response.getOutputStream();ImageIO.write(bufferedImage, "jpg", outputStream);outputStream.flush();} catch (IOException e) {log.error("验证码模块-获取图形验证码异常:{}", e);}finally {try {if (outputStream != null) {outputStream.close();}} catch (IOException e) {log.error("验证码模块-获取图形验证码异常:{}", e);}}
try-with-resources 、try-catch-finally的区别
1. 设计目的
try-with-resources: 专门用于自动管理实现了 AutoCloseable 接口的资源
try-catch-finally: 通用的异常处理和资源清理机制
2. 代码简洁性
try-with-resources: 代码更简洁,减少样板代码
try-catch-finally: 需要手动编写资源关闭逻辑
3. 异常处理
try-with-resources: 自动处理关闭异常,支持抑制异常(suppressed exceptions)
try-catch-finally: 需要手动处理关闭时可能发生的异常
4. 适用场景
try-with-resources: 适用于 AutoCloseable 资源(如流、连接、文件等)
try-catch-finally: 适用于所有需要清理操作的场景