一、使用 finally 若是建立 FileInputstream实例就会开启文档,不使用时,应该调用 close()关闭文档。 Fileutil中是经过 Scanner搭配 FileInputstream来读取文档,实际上 Scanner()对象有个 close()方法,能够关闭 Scanner相关资源与搭配的Fileinputstream。 例如:java
package errorDemo; import java.io.*; import java.util.*; public class FileUtil { public static String readFile(String name) throws FileNotFoundException { StringBuilder txt = new StringBuilder(); Scanner scan = new Scanner(new FileInputStream(name)); while (scan.hasNext()) { txt.append(scan.nextLine()).append('\n'); } scan.close(); return txt.toString(); } }
若是 scanner. close()前发生了任何异常,执行流程就会中断,所以 scanner. close()就可能不会执行,所以 Scanner搭配的 Fileinputstream?就不会被关闭。 你想要的是不管如何,最后必定要执行关闭资源的动做,try、 catch语法还能够搭配finally,不管try区块中有无发生异常,若撰写有 finally区块,则finally区块必定会被执行。例如:app
package errorDemo; import java.io.*; import java.util.*; public class FileUtil { public static String readFile(String name) throws FileNotFoundException { StringBuilder txt = new StringBuilder(); Scanner scan = null; try { scan = new Scanner(new FileInputStream(name)); while (scan.hasNext()) { txt.append(scan.nextLine()).append('\n'); } } finally { if(scan!=null) { scan.close(); } } return txt.toString(); } }
因为finaly区块必定会被执行,这个范例中 scanner原先是null,若 FileInputStream建立失败,则 scanner就有可能仍是null,所以在 finally区块中必须先检查 scanner是否有参考对象,有的话才进一步调用 close()方法,不然scanner参考至null又打算调用close方法,反而会抛出 NullPointerException。 若是程序撰写的流程中先return了,并且也有finally区块,那 finally区块会先执行完后,再将值返回。例如,下面这个会先显示 ggg再显示1:ide
package errorDemo; public class FinallyDemo { public static void main(String[] args) { System.out.println(test(true)); } static int test(boolean flag) { try { if(flag) { return 1; } } finally { // TODO: handle finally clause System.out.println("ggg"); } return 0; } }
二、自动尝试关闭资源 在使用try、 finally尝试关闭资源时,会发现程序撰写的流程是相似的,就如先前 FileUtil,你会先检查 scanner是否为null,再调用close()方法关闭 Scanner。在JDK7以后,新增了尝试关闭资源 (try-with- Resources)语法ui
package errorDemo; import java.io.*; import java.util.*; public class FileUtil2 { public static String readFile(String name) throws FileNotFoundException { StringBuilder txt = new StringBuilder(); try (Scanner scan = new Scanner(new FileInputStream(name))) { while (scan.hasNext()) { txt.append(scan.nextLine()).append('\n'); } } return txt.toString(); } }
想要尝试自动关闭资源的对象,是撰写在try以后的括号中,若是无须 catch处理任何异常,能够不用撰写,也不用撰写finally自行尝试关闭资源。JDK7的尝试关闭资源语法是编译程序蜜糖,尝试反编译:code
... public class FileUtil2 { public static String readFile(String name) throws FileNotFoundException { StringBuilder txt = new StringBuilder(); Scanner scan = new Scanner(new FileInputStream(name)); Throwable localThrowable2 = null; try{ while (scan.hasNext()) { txt.append(scan.nextLine()).append('\n'); } }catch(Throwable LocalThrowable1){//捕捉全部错误 localThrowable2 = LocalThrowable1; throw LocalThrowable1; } finally{ if(scan!=null){//若是scan参考了Scanner实例 if(localThrowable2!=null){//若前面catch到其余异常 try{ scan.close();//尝试关闭Scanner实例 }catch(Throwable x2){//万一关闭时发生错误 localThrowable2.addSuppressed(x2);//在原异常对象中记录 } }else{ scan.close();//若前面没有发生任何异常,直接关闭 } } } return txt.toString(); } }
若一个异常被 catch后的处理过程引起另外一个异常,一般会抛出第一个异常做为响应, addSuppresse()方法是JDKT在java.lang.Throwable中新增的方法,可将第二个异常记录在第一个异常之中,JDK7中与之相对应的是 getSuppressed()方法,可返回 Throwable[],表明先前被addSuppressed()记录的各个异常对象。
使用自动尝试关闭资源语法时,也能够搭配 catch。如在发生FileNotFoundException 时显示堆栈追踪信息:对象
public static String readFile(String name) throws FileNotFoundException { StringBuilder txt = new StringBuilder(); try (Scanner scan = new Scanner(new FileInputStream(name))) { while (scan.hasNext()) { txt.append(scan.nextLine()).append('\n'); } }catch(FileInputStream e){ e.printStackTrace(); throw e; } return txt.toString(); }
使用JAD反编译后能够看到,实际上前一个反编译程序片断中一部分,是产生在另外一个try、 catch区块中:接口
... public class FileUtil2 { public static String readFile(String name) throws FileNotFoundException { StringBuilder txt = new StringBuilder(); try{ Scanner scan = new Scanner(new FileInputStream(name)); Throwable localThrowable2 = null; try { while (scan.hasNext()) { txt.append(scan.nextLine()).append('\n'); } }catch(Throwable LocalThrowable1){ localThrowable2 = LocalThrowable1; throw LocalThrowable1; } finally{ if(scan!=null){ if(localThrowable2!=null){ try{ scan.close(); }catch(Throwable x2){ localThrowable2.addSuppressed(x2); } }else{ scan.close(); } } } }catch(FileInputStream ex){ ex.printStackTrace(); throw ex; } return txt.toString(); } }
使用自动尝试关闭资源语法时,并不影响你对特定异常的处理。自动尝试关闭资源语法仅协助你关闭资源,而非用于处理异常。从反编译的程序代码中也能够看到,使用尝试关闭资源语法时,不要试图自行撰写程序代码关闭资源,这样会形成重复调用close()方法。 3 、java. lang. AutoCloseable JDK7的尝试关闭资源语法可套用的对象,必须操做java.lang. AutoCloseable接口。它是JDK7新增的仅定义了close()的接口。 只要操做AutoCloseable接口就能够套用至尝试自动关闭资源语法:资源
package errorDemo; public class AutoCloseableDemo { public static void main(String[] args) { try (Resource res=new Resource()){//括号内执行完自动关闭 res.doSome(); } catch (Exception e) { e.printStackTrace(); } } } class Resource implements AutoCloseable{ void doSome() { System.out.println("gggg"); } @Override public void close() throws Exception { System.out.println("资源关闭"); } }
执行结果:gggg 资源关闭 尝试自动关闭资源语法能够关闭两个以上对象资源,中间以分号分开:文档
package errorDemo; public class AutoCloseableDemo { public static void main(String[] args) { try (Resource res = new Resource(); Resource2 res2 = new Resource2()) {//try区间执行完毕后统一关闭资源 res.doSome(); res2.doOther(); } catch (Exception e) { e.printStackTrace(); } } } class Resource implements AutoCloseable { void doSome() { System.out.println("some"); } @Override public void close() throws Exception { System.out.println("资源关闭"); } } class Resource2 implements AutoCloseable { void doOther() { System.out.println("other"); } @Override public void close() throws Exception { System.out.println("资源2关闭"); } }
执行结果:some other 资源2关闭 资源关闭 try括号中,越后面的对象资源越早被关闭。反编译发现每一个AutoCloseable对象,都独立使用一个try、catch、finally,try括号越后面的对象会越在内层的try、catch、finally中。get