欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-25 13:50:36
目录java try()语句实现try-with-resources异常管理机制自定义autocloseable实现java try()语句实现try-with-resources异常管理机制java...

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语句。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。