Java8里的一个新语法特性:try-with-resources。
这个语法特性其实从java7里就有了,不过java8的sample里依然有这个。
try-with-resources的特性就是,在try( …)里声明的资源,会在try-catch代码块结束后自动关闭掉。
废话不说,先上代码后分析。
public class AutoCloseTest {
public static void main(String[] args) {
testNormalOutput(args[0]);
testAutoCloseWithTryCatch(args[1]);
}
private static void testNormalOutput(String filepath){
OutputStream global_out = null;
BufferedWriter writer ;
try {
OutputStream out = out = new FileOutputStream(filepath);
global_out = out;
out.write((filepath + "inside try catch block").getBytes());
} catch (Exception e) {
e.printStackTrace();
}
try{
if(global_out!=null){
global_out.write(" \t\r outside try catch block".getBytes());
global_out.close();
}
} catch (Exception e){
e.printStackTrace();
}
}
private static void testAutoCloseWithTryCatch(String filepath){
OutputStream global_out = null;
try(OutputStream out = new FileOutputStream(filepath);) {
global_out = out;
out.write((filepath+"inside try catch block").getBytes());
} catch (Exception e) {
e.printStackTrace();
}
try{
if(global_out!=null){
global_out.write(" \t\r outside try catch block".getBytes());
global_out.close();
}
} catch (Exception e){
e.printStackTrace();
}
}
}
运行
java AutoCloseTest d:/a.txt d:/b.txt
然后发现
a.txt里的内容是
d:/a.txt inside try catch block outside try catch block
b.txt里的内容是
d:/b.txt inside try catch block
没错,b.txt的后半段代码没有执行 同时控制台还打印出
java.io.IOException: Stream Closed
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:294)
at trywithresources.AutoCloseTest.testAutoCloseWithTryCatch(AutoCloseTest.java:46)
at trywithresources.AutoCloseTest.main(AutoCloseTest.java:11)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
这是因为在testAutoCloseWithTryCatch方法里,global_out所指向的out对象已经在第一次try-catch之后被关闭了 在第二次对这个已经关闭的流里输出内容时,就会报Stream Closed错误。
——————–*************************———————–********************
那么try-with-resources是如何工作的呢?它和finally的工作谁在前呢?我们可以做一个小测试
private static void testAutoClose() {
AutoCloseable global_obj1 = null;
AutoCloseable global_obj2 = null;
try(AutoCloseable obj1 = new AutoClosedImpl("obj1");
AutoCloseable obj2 = new AutoClosedImpl("obj2");){
global_obj1= obj1;
int i = 1/0;
global_obj2= obj2;
} catch (Exception e) {
e.printStackTrace();
}finally{
try{
System.out.println("before finally close");
if(global_obj1!=null){
global_obj1.close();
}
if(global_obj2!=null){
global_obj2.close();
}
System.out.println("after finally close");
} catch(Exception e){
e.printStackTrace();
}
}
}
private static class AutoClosedImpl implements AutoCloseable{
private String name;
public AutoClosedImpl(String name){
this.name = name;
}
@Override
public void close() throws Exception {
System.out.println(name+" closing");
}
}
执行testAutoClose()方法,会打印出如下结果
obj2 closing
obj1 closing
before finally close
obj1 closing
after finally close
java.lang.ArithmeticException: / by zero
at trywithresources.AutoCloseTest.testAutoClose(AutoCloseTest.java:60)
at trywithresources.AutoCloseTest.main(AutoCloseTest.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
从上述代码我们可以观测四件事 1. 凡是实现了AutoCloseable接口的类,在try()里声明该类实例的时候,在try结束后,close方法都会被调用 2. try结束后自动调用的close方法,这个动作会早于finally里调用的方法。 3. 不管是否出现异常(int i=1/0会抛出异常),try()里的实例都会被调用close方法 4. 越晚声明的对象,会越早被close掉。