try-with-resource 關閉資源
Try-with-resources
Try-with-resources是Java7中一個新的異常處理機制,它能夠很容易地關閉在try-catch語句塊中使用的資源。
舊的程式碼風格,傳統的try-catch-finally
private static void printFile() throws IOException {
InputStream input = null;
try {
input = new FileInputStream("file.txt");
int data = input.read();
while(data != -1){
System.out.print((char) data);
data = input.read();
}
}catch(Exception e){
log.info(e.getMessage)
}
finally {
if(input != null){
input.close();
}
}
}
不論try語句塊中是否有異常丟擲,finally語句塊始終會被執行。這意味著,不論try語句塊中發生什麼,InputStream 都會被關閉,或者說都會試圖被關閉。如果關閉失敗,InputStream close()方法也可能會丟擲異常。
假設try語句塊丟擲一個異常,然後finally語句塊被執行。同樣假設finally語句塊也丟擲了一個異常。那麼哪個異常會根據呼叫棧往外傳播?即使try語句塊中丟擲的異常與異常傳播更相關,最終還是finally語句塊中丟擲的異常會根據呼叫棧向外傳播。
用try-with-resource 結構寫
private static void printFileJava7() {
try (
FileInputStream input = new FileInputStream("file.txt")
) {
int data = input.read();
while (data != -1) {
System.out.print((char) data);
data = input.read();
}
} catch (Exception e) {
e.printStackTrace();
}
}
try(FileInputStream input = new FileInputStream(“file.txt”)) 就是try-with-resource 結構的用法。FileInputStream 型別變數就在try關鍵字後面的括號中宣告,一個FileInputStream 型別被例項化並被賦給了這個變數。
當try語句塊執行結束時,FileInputStream 會被自動關閉。這是因為FileInputStream 實現了java中的java.lang.AutoCloseable介面。所有實現了這個介面的類都可以在try-with-resources結構中使用。
異常傳播:
當try-with-resources結構中丟擲一個異常,同時FileInputStreami被關閉時(呼叫了其close方法)也丟擲一個異常。try-with-resources結構中丟擲的異常會向外傳播,而FileInputStreami被關閉時丟擲的異常被抑制了。這與舊風格程式碼的例子(在finally語句塊中關閉資源)相反。
使用多個資源
/**
* 上傳單個檔案
*
* @param file 檔案的控制代碼
* @param outputPath 輸出的最終檔案地址
*/
public void saveFile(MultipartFile file, String outputPath) {
try (
FileInputStream fis = (FileInputStream) file.getInputStream();
FileOutputStream fos = new FileOutputStream(outputPath);
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel();
) {
//通道間傳輸資料
inChannel.transferTo(0, inChannel.size(), outChannel);
} catch (Exception e) {
logger.info("儲存檔案失敗:{}", e.getMessage());
}
}
當程式執行離開try語句塊時,所有資源都會被自動關閉。這些資源將按照他們被建立順序的逆序來關閉。首先outChannel會被關閉,然後inChannel、fos、fis會被關閉。
自定義 AutoCloseable 實現
這個try-with-resources結構裡不僅能夠操作java內建的類。你也可以在自己的類中實現java.lang.AutoCloseable介面,然後在try-with-resources結構裡使用這個類。
package t1;
public class MyClose1 implements AutoCloseable {
public void doIt() {
System.out.println("MyClose1 doing!");
}
@Override
public void close() throws Exception {
System.out.println("MyClose1 Closed!");
}
}
package t1;
public class MyClose2 implements AutoCloseable {
public void doIt() {
System.out.println("MyClose2 doing!");
}
@Override
public void close() throws Exception {
System.out.println("MyClose2 Closed!");
}
}
測試執行:
package t1;
/**
* @author zhe.xiao
* @date 2020-12-07
* @description
*/
public class Test {
public static void main(String[] args) {
try (
MyClose1 mc1 = new MyClose1();
MyClose2 mc2 = new MyClose2();
) {
mc1.doIt();
mc2.doIt();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
列印: