在Java編程過程中,如果打開了外部資源(文件、數(shù)據(jù)庫(kù)連接、網(wǎng)絡(luò)連接等),我們必須在這些外部資源使用完畢后,手動(dòng)關(guān)閉它們。 (推薦學(xué)習(xí):java課程)
因?yàn)橥獠抠Y源不由JVM管理,無法享用JVM的垃圾回收機(jī)制,如果我們不在編程時(shí)確保在正確的時(shí)機(jī)關(guān)閉外部資源,就會(huì)導(dǎo)致外部資源泄露,緊接著就會(huì)出現(xiàn)文件被異常占用,數(shù)據(jù)庫(kù)連接過多導(dǎo)致連接池溢出等諸多很嚴(yán)重的問題。
為了確保外部資源一定要被關(guān)閉,通常關(guān)閉代碼被寫入finally代碼塊中,當(dāng)然我們還必須注意到關(guān)閉資源時(shí)可能拋出的異常,于是變有了下面的經(jīng)典代碼
public static void main(String[] args) { FileInputStream inputStream = null; try { inputStream = new FileInputStream(new File("test")); System.out.println(inputStream.read()); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } } } }
換成try-with-resource
public static void main(String[] args) { try (FileInputStream inputStream = new FileInputStream(new File("test"))) { System.out.println(inputStream.read()); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } }
再以一個(gè)java里面讀取文件和寫入文件為例子
/** * @ Author zhangsf * @CreateTime 2019/11/27 - 13:05 */ package Advanced; import java.io.File; import java.io.InputStreamReader; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileWriter; public class ReadTxt1 { public static void main(String args[]) { try { // 防止文件建立或讀取失敗,用catch捕捉錯(cuò)誤并打印,也可以throw /* 讀入TXT文件 */ String pathname = "E:\python_file\web_spider\input.txt"; // 絕對(duì)路徑或相對(duì)路徑都可以,這里是絕對(duì)路徑,寫入文件時(shí)演示相對(duì)路徑 File filename = new File(pathname); // 要讀取以上路徑的input。txt文件 InputStreamReader reader = new InputStreamReader( new FileInputStream(filename)); // 建立一個(gè)輸入流對(duì)象reader BufferedReader br = new BufferedReader(reader); // 建立一個(gè)對(duì)象,它把文件內(nèi)容轉(zhuǎn)成計(jì)算機(jī)能讀懂的語言 String line = ""; line = br.readLine(); while (line != null) { line = br.readLine(); // 一次讀入一行數(shù)據(jù) System.out.println(line); } /* 寫入Txt文件 */ File writename = new File("E:\python_file\web_spider\output.txt"); // 相對(duì)路徑,如果沒有則要建立一個(gè)新的output。txt文件 writename.createNewFile(); // 創(chuàng)建新文件 BufferedWriter out = new BufferedWriter(new FileWriter(writename)); out.write("開始寫入文件啦rn"); // rn即為換行 out.flush(); // 把緩存區(qū)內(nèi)容壓入文件 out.close(); // 最后記得關(guān)閉文件 } catch (Exception e) { e.printStackTrace(); } } }
當(dāng)一個(gè)外部資源的句柄對(duì)象實(shí)現(xiàn)了AutoCloseable接口,JDK7中便可以利用try-with-resource語法更優(yōu)雅的關(guān)閉資源,消除板式代碼。
在JDK7以前,Java沒有自動(dòng)關(guān)閉外部資源的語法特性,直到JDK7中新增了try-with-resource語法,那么將上面java的讀文件和寫文件重新按照try-with-resource語法實(shí)現(xiàn)
/** * @ Author zhangsf * @CreateTime 2019/11/27 - 11:44 */ package Advanced; import java.io.*; public class ReadTxt { public static void main(String args[]) { readFile(); writeFile(); } /** * 讀入TXT文件 */ public static void readFile() { String pathname = "E:\python_file\web_spider\input.txt"; // 絕對(duì)路徑或相對(duì)路徑都可以,寫入文件時(shí)演示相對(duì)路徑, // 讀取以上路徑的input.txt文件 //防止文件建立或讀取失敗,用catch捕捉錯(cuò)誤并打印,也可以throw; //不關(guān)閉文件會(huì)導(dǎo)致資源的泄露,讀寫文件都同理 //Java7的try-with-resources可以優(yōu)雅關(guān)閉文件,異常時(shí)自動(dòng)關(guān)閉文件;詳細(xì)解讀https://stackoverflow.com/a/12665271 try (FileReader reader = new FileReader(pathname); BufferedReader br = new BufferedReader(reader) // 建立一個(gè)對(duì)象,它把文件內(nèi)容轉(zhuǎn)成計(jì)算機(jī)能讀懂的語言 ) { String line; //推薦更加簡(jiǎn)潔的寫法 while ((line = br.readLine()) != null) { // 一次讀入一行數(shù)據(jù) System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } /** * 寫入TXT文件 */ public static void writeFile() { try { File writeName = new File("E:\python_file\web_spider\output2.txt"); // 相對(duì)路徑,如果沒有則要建立一個(gè)新的output.txt文件 writeName.createNewFile(); // 創(chuàng)建新文件,有同名的文件的話直接覆蓋 try (FileWriter writer = new FileWriter(writeName); BufferedWriter out = new BufferedWriter(writer) ) { out.write("我開始寫入文件啦1rn"); // rn即為換行 out.write("我開始寫入文件啦2rn"); // rn即為換行 out.flush(); // 把緩存區(qū)內(nèi)容壓入文件 } } catch (IOException e) { e.printStackTrace(); } } }
將外部資源的句柄對(duì)象的創(chuàng)建放在try關(guān)鍵字后面的括號(hào)中,當(dāng)這個(gè)try-catch代碼塊執(zhí)行完畢后,Java會(huì)確保外部資源的close方法被調(diào)用。簡(jiǎn)潔很多。
try-with-resource語法涉及的另外一個(gè)知識(shí)點(diǎn),叫做異常抑制。當(dāng)對(duì)外部資源進(jìn)行處理(例如讀或?qū)懀r(shí),如果遭遇了異常,且在隨后的關(guān)閉外部資源過程中,又遭遇了異常,那么你catch到的將會(huì)是對(duì)外部資源進(jìn)行處理時(shí)遭遇的異常,關(guān)閉資源時(shí)遭遇的異常將被“抑制”但不是丟棄,通過異常的getSuppressed方法,可以提取出被抑制的異常。
try-with-resource時(shí),如果對(duì)外部資源的處理和對(duì)外部資源的關(guān)閉均遭遇了異常,“關(guān)閉異常”將被抑制,“處理異?!睂⒈粧伋觯瓣P(guān)閉異?!辈]有丟失,而是存放在“處理異?!钡谋灰种频漠惓A斜?/p>