Java try()语句实现try-with-resources异常管理机制操作

作者:bsbhenry 时间:2022-02-06 18:29:16 

Java try()语句实现try-with-resources异常管理机制

java7 新增特性,对于try语句块中使用到的资源,不再需要手动关闭,在语句块结束后,会自动关闭,类似于python的with..as的用法。

利用这个特性,需要实现AutoCloseable接口,只有一个close方法,实现关闭资源的操作。


public interface AutoCloseable{
   public void close() throws Exception;
}

所有的流,都实现了这个接口,可以在try()中进行实例化。自定义的类只要实现了这个接口,也可以使用这个特性。

不使用try-with-resources时,使用的资源要在finally中进行释放


package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestStream {
   public static void main(String[] args) {
       File f = new File("d:/test.txt");
       FileInputStream fis = null;
       try {
           fis = new FileInputStream(f);
       } catch (IOException e) {
           e.printStackTrace();
       } finally {
           // 在finally 里关闭流
           if (null != fis)
               try {
                   fis.close();
               } catch (IOException e) {
                   // TODO Auto-generated catch block
                   e.printStackTrace();
               }
       }
   }
}

使用try-with-resources时

形式为try(),括号内可以包含多个语句。


package stream;  
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;  
public class TestStream {  
   public static void main(String[] args) {
       File f = new File("d:/lol.txt");

//把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
       try (FileInputStream fis = new FileInputStream(f)) {
           byte[] all = new byte[(int) f.length()];
           fis.read(all);
           for (byte b : all) {
               System.out.println(b);
           }
       } catch (IOException e) {
           e.printStackTrace();
       }  
   }
}

自定义AutoCloseable实现

在TestAutoCloseable的close方法中打印信息


package test;
public class TestAutoCloseable implements AutoCloseable{
public TestAutoCloseable() {
 System.out.println("class TestAutoCloceable");
}
public void close() {
 System.out.println("function close() executed");
}
}

测试代码


package test;
public class TestFeature {
public static void main(String[] args) {
 // TODO Auto-generated method stub
 try(TestAutoCloseable testAutoCloseable = new TestAutoCloseable()){  
 }
}
}

结果close方法被调用

Java try()语句实现try-with-resources异常管理机制操作

try-with-resources语句优雅的关闭资源

在Java编程过程中,如果打开了外部资源(文件、数据库连接、网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们。

因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在编程时确保在正确的时机关闭外部资源,就会导致外部资源泄露,紧接着就会出现文件被异常占用,数据库连接过多导致连接池溢出等诸多很严重的问题。

在java1.7以前,我们关闭资源的方式如下


public class CloseTest {
   public static void main(String[] args){
       FileInputStream fileInputStream = null;
       try {
           fileInputStream = new FileInputStream("file.txt");
           fileInputStream.read();
       } catch (IOException e) {
           e.printStackTrace();
       }finally {
           if (fileInputStream != null){
               try {
                   fileInputStream.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
       }
   }
}

为了确保外部资源一定要被关闭,通常关闭代码被写入finally代码块中,关闭资源时可能抛出的异常,于是经典代码就诞生了。

但是,在java1.7版本之后,新增加了一个语法糖,就是try-with-resources语句,

我们先直接上一个demo,方便理解


public class CloseTest {
   public static void main(String[] args) {
       try (FileInputStream fileInputStream1 = new FileInputStream("file1.txt");
            FileInputStream fileInputStream2 = new FileInputStream("file2.txt")) {
           fileInputStream1.read();
           fileInputStream2.read();
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
}

将外部资源的句柄对象的创建放在try关键字后面的括号中,当这个try-catch代码块执行完毕后,Java会确保外部资源的close方法被调用。多个语句使用分号断开。

反编译之后我们可以看见


public static void main(String[] args) {
 try {
   FileInputStream inputStream = new FileInputStream(new File("test"));
   Throwable var2 = null;

try {
     System.out.println(inputStream.read());
   } catch (Throwable var12) {
     var2 = var12;
     throw var12;
   } finally {
     if (inputStream != null) {
       if (var2 != null) {
         try {
           inputStream.close();
         } catch (Throwable var11) {
           var2.addSuppressed(var11);
         }
       } else {
         inputStream.close();
       }
     }
   }
 } catch (IOException var14) {
   throw new RuntimeException(var14.getMessage(), var14);
 }
}

通过反编译的代码,大家可能注意到代码中有一处对异常的特殊处理:


var2.addSuppressed(var11);

这是try-with-resource语法涉及的另外一个知识点,叫做异常抑制。当对外部资源进行处理(例如读或写)时,如果遭遇了异常,且在随后的关闭外部资源过程中,又遭遇了异常,那么你catch到的将会是对外部资源进行处理时遭遇的异常,关闭资源时遭遇的异常将被“抑制”但不是丢弃,通过异常的getSuppressed方法,可以提取出被抑制的异常。

源码里面有解释


/**
    * Returns an array containing all of the exceptions that were
    * suppressed, typically by the {@code try}-with-resources
    * statement, in order to deliver this exception.
    *
    * If no exceptions were suppressed or {@linkplain
    * #Throwable(String, Throwable, boolean, boolean) suppression is
    * disabled}, an empty array is returned.  This method is
    * thread-safe.  Writes to the returned array do not affect future
    * calls to this method.
    *
    * @return an array containing all of the exceptions that were
    *         suppressed to deliver this exception.
    * @since 1.7
    */
   public final synchronized Throwable[] getSuppressed() {
       if (suppressedExceptions == SUPPRESSED_SENTINEL ||
           suppressedExceptions == null)
           return EMPTY_THROWABLE_ARRAY;
       else
           return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
   }

总结一下吧

因为不管什么情况下(异常或者非异常)资源都必须关闭,在jdk1.6之前,应该把close()放在finally块中,以确保资源的正确释放。如果使用jdk1.7以上的版本,推荐使用try-with-resources语句。

来源:https://blog.csdn.net/bsbhenry/article/details/87557792

标签:Java,try,try-with-resources,异常管理
0
投稿

猜你喜欢

  • Java的RxJava库操作符的用法及实例讲解

    2021-12-14 22:31:41
  • spring cloud consul注册的服务报错critical的解决

    2021-05-28 14:13:14
  • java实现短地址服务的方法(附代码)

    2023-11-15 19:13:41
  • Java Servlet3.0异步处理问题

    2023-08-12 00:52:05
  • Java开发中可以防止界面假死的刷新代码

    2023-11-23 22:23:41
  • C# WPF 自定义按钮的方法

    2021-08-30 23:42:11
  • 聊聊@RequestMapping和@GetMapping @PostMapping的区别

    2021-07-26 19:20:43
  • Java Volatile关键字你真的了解吗

    2023-08-09 20:28:23
  • Mybatis中注解@MapKey的使用详解

    2023-11-24 21:43:35
  • C#实现DataTable映射成Model的方法(附源码)

    2023-03-12 06:10:56
  • 深入理解java虚拟机的故障处理工具

    2023-11-20 06:41:58
  • java集合迭代器Iterator中的remove陷阱

    2022-06-17 16:11:54
  • Java线程安全解决方案(synchronized,ReentrantLock,Atomic)

    2022-06-13 12:51:09
  • SpringBoot整合WebSocket实现聊天室流程全解

    2021-07-03 23:35:21
  • Java泛型的使用限制实例分析

    2023-05-07 20:14:52
  • springboot2.0整合dubbo的示例代码

    2021-11-30 06:07:11
  • SpringBoot整合WebService的实现示例

    2023-05-25 12:37:55
  • 详解Spring Boot Oauth2缓存UserDetails到Ehcache

    2023-02-26 21:57:12
  • SpringBoot和Swagger结合提高API开发效率

    2023-11-25 01:23:16
  • Java中的动态和静态编译实例详解

    2021-07-30 15:25:10
  • asp之家 软件编程 m.aspxhome.com