1. 程式人生 > >java8學習第二篇:try-with-resources

java8學習第二篇:try-with-resources

Java8裡的一個新語法特性:try-with-resources。

這個語法特性其實從java7裡就有了,不過java8的sample裡依然有這個。

try-with-resources的特性就是,在try( ...)裡宣告的資源,會在try-catch程式碼塊結束後自動關閉掉。

廢話不說,先上程式碼後分析。

  1. public class AutoCloseTest {

  2. public static void main(String[] args) {

  3. testNormalOutput(args[0]);

  4. testAutoCloseWithTryCatch(args[1]);

  5. }

  6. private static void testNormalOutput(String filepath){

  7. OutputStream global_out = null;

  8. BufferedWriter writer ;

  9. try {

  10. OutputStream out = out = new FileOutputStream(filepath);

  11. global_out = out;

  12. out.write((filepath + "inside try catch block").getBytes());

  13. } catch (Exception e) {

  14. e.printStackTrace();

  15. }

  16. try{

  17. if(global_out!=null){

  18. global_out.write(" \t\r outside try catch block".getBytes());

  19. global_out.close();

  20. }

  21. } catch (Exception e){

  22. e.printStackTrace();

  23. }

  24. }

  25. private static void testAutoCloseWithTryCatch(String filepath){

  26. OutputStream global_out = null;

  27. try(OutputStream out = new FileOutputStream(filepath);) {

  28. global_out = out;

  29. out.write((filepath+"inside try catch block").getBytes());

  30. } catch (Exception e) {

  31. e.printStackTrace();

  32. }

  33. try{

  34. if(global_out!=null){

  35. global_out.write(" \t\r outside try catch block".getBytes());

  36. global_out.close();

  37. }

  38. } catch (Exception e){

  39. e.printStackTrace();

  40. }

  41. }

  42. }

執行

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的後半段程式碼沒有執行

同時控制檯還打印出

  1. java.io.IOException: Stream Closed

  2. at java.io.FileOutputStream.writeBytes(Native Method)

  3. at java.io.FileOutputStream.write(FileOutputStream.java:294)

  4. at trywithresources.AutoCloseTest.testAutoCloseWithTryCatch(AutoCloseTest.java:46)

  5. at trywithresources.AutoCloseTest.main(AutoCloseTest.java:11)

  6. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  7. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

  8. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  9. at java.lang.reflect.Method.invoke(Method.java:483)

  10. at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

這是因為在testAutoCloseWithTryCatch方法裡,global_out所指向的out物件已經在第一次try-catch之後被關閉了

在第二次對這個已經關閉的流裡輸出內容時,就會報Stream Closed錯誤。

--------------------*************************-----------------------********************

那麼try-with-resources是如何工作的呢?它和finally的工作誰在前呢?我們可以做一個小測試

  1. private static void testAutoClose() {

  2. AutoCloseable global_obj1 = null;

  3. AutoCloseable global_obj2 = null;

  4. try(AutoCloseable obj1 = new AutoClosedImpl("obj1");

  5. AutoCloseable obj2 = new AutoClosedImpl("obj2");){

  6. global_obj1= obj1;

  7. int i = 1/0;

  8. global_obj2= obj2;

  9. } catch (Exception e) {

  10. e.printStackTrace();

  11. }finally{

  12. try{

  13. System.out.println("before finally close");

  14. if(global_obj1!=null){

  15. global_obj1.close();

  16. }

  17. if(global_obj2!=null){

  18. global_obj2.close();

  19. }

  20. System.out.println("after finally close");

  21. } catch(Exception e){

  22. e.printStackTrace();

  23. }

  24. }

  25. }

  26. private static class AutoClosedImpl implements AutoCloseable{

  27. private String name;

  28. public AutoClosedImpl(String name){

  29. this.name = name;

  30. }

  31. @Override

  32. public void close() throws Exception {

  33. System.out.println(name+" closing");

  34. }

  35. }

執行testAutoClose()方法,會打印出如下結果

  1. obj2 closing

  2. obj1 closing

  3. before finally close

  4. obj1 closing

  5. after finally close

  6. java.lang.ArithmeticException: / by zero

  7. at trywithresources.AutoCloseTest.testAutoClose(AutoCloseTest.java:60)

  8. at trywithresources.AutoCloseTest.main(AutoCloseTest.java:12)

  9. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  10. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

  11. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  12. at java.lang.reflect.Method.invoke(Method.java:483)

  13. 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掉。