Java基礎學習總結(136)——有關流資源關閉(try-with-resources與AutoCloseable)的使用總結
前言
做Java開發的都知道,每個資源的開啟都需要對應的關閉操作,不然就會使資源一直佔用而造成資源浪費,從而降低系統性能。關於資源的關閉操作,從JDK7-JDK9有了不少的提升及簡化。我們來看看資源處理的變化。
一、JDK6
在JDK6及之前,每個資源都需要我們手動寫程式碼關閉,如:
FileInputStream fis = null; byte[] buffer = new byte[1024]; try { fis = new FileInputStream(new File("E:\Java檔案.txt")); while (fis.read(buffer) > 0) { System.out.println(new String(buffer)); } } catch(Exception e) { e.printStackTrace(); }finally{ if(fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } }
資源開啟使用完後,必須在finally塊中進行手動關閉!尤其是資料庫的連線物件Connection。我們有的同事,做一個查詢功能點,打開了連線查詢完後沒有手動關閉,最後造成連線池超出最大連線數而使系統功能堵塞。
二、JDK7
JDK7釋出後,添加了新特性:try-with-resources語句。所有需要關閉的資源只要實現了 java.lang.AutoCloseable(java.io.Closeable就實現了這個介面)介面就會在程式結束後自動關閉。AutoCloseable介面在JDK7中引入的,看原始碼,其中只有一個方法:
void close() throws Exception;
如上面的讀取檔案的流程式用JDK7來寫:
byte[] buffer = new[1024];
try (FileInputStream fis = new FileInputStream(new File("E:\Java檔案.txt"))) {
while (fis.read(buffer) > 0) {
System.out.println(new String(buffer));
}
} catch (Exception e) {
e.printStackTrace();
}
所有的資源在 try()裡面定義,並去掉了finally模組。最後程式會自動關閉資源(本例中的檔案流fis物件)。下面我們來寫一個自定義的流來看看是否自動關閉了。簡單示例。
定義一個自定義輸入輸出流
class MyInputStream implements AutoCloseable {
void read(String content) {
System.out.println("Read content " + content);
}
@Override
public void close() throws Exception {
System.out.println("Input stream is closed.");
}
}
class MyOutputStream implements AutoCloseable {
void write(String content) {
System.out.println("write content " + content);
}
@Override
public void close() throws Exception {
System.out.println("out stream is closed.");
}
}
單個資源自動關閉
try (MyInputStream mis = new MyInputStream()) {
mis.read("MyInputStream");
} catch (Exception e) {
e.printStackTrace();
}
輸出:
read content MyInputStream
Input stream is closed.
多個資源自動關閉
try()裡面可以定義多個資源,它們的關閉順序是最後在 try()定義的資源先關閉。
try (MyInputStream mis = new MyInputStream(); MyOutputStream mos = new MyOutputStream()) {
mis.read("ND");
mos.write("ND");
} catch (Exception e) {
e.printStackTrace();
}
輸出:
Read content NDwrite content NDout stream is closed.Input stream is closed.
三、JDK9
JDK9釋出後,又簡化了try-with-resources語句的用法。try()裡面可以是一個變數,但必須是final的或者等同final才行。如下面的mis,mos定義成區域性變數可以不用final,區域性變數可以等同於final,但定義成成員變數就必須是用final修飾的,不然會編譯錯誤。也就是說,資源不要在try後的括號內建立,而是提前建立,滿足上面的條件,在try後的括號內直接使用變數即可。
MyInputStream mis = new MyInputStream();
MyOutputStream mos = new MyOutputStream();
try (mis; mos) {
mis.read("1.9");
mos.write("1.9");
} catch (Exception e) {
e.printStackTrace();
}
輸出:
Read content 1.9write content 1.9out stream is closed.Input stream is closed.
再來看個示意性例子:
Connection dbCon = DriverManager.getConnection("url", "user", "password");
try (dbCon; ResultSet rs = dbCon.createStatement().executeQuery("select * from emp")) {
while (rs.next()) {
System.out.println("In loadDataFromDB() =====>>>>>>>>>>>> " + rs.getString(1));
}
}catch (SQLException e) {
System.out.println("Exception occurs while reading the data from DB ->" + e.getMessage());
}
dbCon和rs都能被自動關閉——檢視原始碼可知,Connection和ResultSet等都實現AutoCloseable介面。
這樣可以在實際編碼時,寫出更簡潔的程式碼,省略很多莫辦事程式碼(finally中關閉各種資料庫相關的物件以及異常處理等)JDK9的這一點變化還是非常有用的,可使開發人員更關注資料的處理方面。