日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Java try-with-resource語法使用解析

瀏覽:34日期:2022-09-04 08:48:27

背景

眾所周知,所有被打開的系統資源,比如流、文件或者Socket連接等,都需要被開發者手動關閉,否則隨著程序的不斷運行,資源泄露將會累積成重大的生產事故。

在Java的江湖中,存在著一種名為finally的功夫,它可以保證當你習武走火入魔之時,還可以做一些自救的操作。在遠古時代,處理資源關閉的代碼通常寫在finally塊中。然而,如果你同時打開了多個資源,那么將會出現噩夢般的場景:

public class Demo { public static void main(String[] args) { BufferedInputStream bin = null; BufferedOutputStream bout = null; try { bin = new BufferedInputStream(new FileInputStream(new File('test.txt'))); bout = new BufferedOutputStream(new FileOutputStream(new File('out.txt'))); int b; while ((b = bin.read()) != -1) {bout.write(b); } } catch (IOException e) { e.printStackTrace(); } finally { if (bin != null) {try { bin.close();}catch (IOException e) { e.printStackTrace();}finally { if (bout != null) { try { bout.close(); } catch (IOException e) { e.printStackTrace(); } }} } } }}

Oh My God?。。£P閉資源的代碼竟然比業務代碼還要多?。。∵@是因為,我們不僅需要關閉BufferedInputStream,還需要保證如果關閉BufferedInputStream時出現了異常, BufferedOutputStream也要能被正確地關閉。所以我們不得不借助finally中嵌套finally大法??梢韵氲?,打開的資源越多,finally中嵌套的將會越深?。?!

更為可惡的是,Python程序員面對這個問題,竟然微微一笑很傾城地說:“這個我們一點都不用考慮的嘞~”:

但是兄弟莫慌!我們可以利用Java 1.7中新增的try-with-resource語法糖來打開資源,而無需碼農們自己書寫資源來關閉代碼。媽媽再也不用擔心我把手寫斷掉了!我們用try-with-resource來改寫剛才的例子:

public class TryWithResource { public static void main(String[] args) { try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(new File('test.txt'))); BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File('out.txt')))) { int b; while ((b = bin.read()) != -1) {bout.write(b); } } catch (IOException e) { e.printStackTrace(); } }}

是不是很簡單?是不是很刺激?再也不用被Python程序員鄙視了!好了,下面將會詳細講解其實現原理以及內部機制。

動手實踐

為了能夠配合try-with-resource,資源必須實現AutoClosable接口。該接口的實現類需要重寫close方法:

public class Connection implements AutoCloseable { public void sendData() { System.out.println('正在發送數據'); } @Override public void close() throws Exception { System.out.println('正在關閉連接'); }}

調用類:

public class TryWithResource { public static void main(String[] args) { try (Connection conn = new Connection()) { conn.sendData(); } catch (Exception e) { e.printStackTrace(); } }}

運行后輸出結果:

正在發送數據正在關閉連接

通過結果我們可以看到,close方法被自動調用了。

原理

那么這個是怎么做到的呢?我相信聰明的你們一定已經猜到了,其實,這一切都是編譯器大神搞的鬼。我們反編譯剛才例子的class文件:

public class TryWithResource { public TryWithResource() { } public static void main(String[] args) { try { Connection e = new Connection(); Throwable var2 = null; try {e.sendData(); } catch (Throwable var12) {var2 = var12;throw var12; } finally {if(e != null) { if(var2 != null) { try { e.close(); } catch (Throwable var11) { var2.addSuppressed(var11); } } else { e.close(); }} } } catch (Exception var14) { var14.printStackTrace(); } }}

看到沒,在第15~27行,編譯器自動幫我們生成了finally塊,并且在里面調用了資源的close方法,所以例子中的close方法會在運行的時候被執行。

異常屏蔽

我相信,細心的你們肯定又發現了,剛才反編譯的代碼(第21行)比遠古時代寫的代碼多了一個addSuppressed。為了了解這段代碼的用意,我們稍微修改一下剛才的例子:我們將剛才的代碼改回遠古時代手動關閉異常的方式,并且在sendData和close方法中拋出異常:

public class Connection implements AutoCloseable { public void sendData() throws Exception { throw new Exception('send data'); } @Override public void close() throws Exception { throw new MyException('close'); }}

修改main方法:

public class TryWithResource { public static void main(String[] args) { try { test(); } catch (Exception e) { e.printStackTrace(); } } private static void test() throws Exception { Connection conn = null; try { conn = new Connection(); conn.sendData(); } finally { if (conn != null) {conn.close(); } } }}

運行之后我們發現:

basic.exception.MyException: closeat basic.exception.Connection.close(Connection.java:10)at basic.exception.TryWithResource.test(TryWithResource.java:82)at basic.exception.TryWithResource.main(TryWithResource.java:7)......

好的,問題來了,由于我們一次只能拋出一個異常,所以在最上層看到的是最后一個拋出的異?!簿褪莄lose方法拋出的MyException,而sendData拋出的Exception被忽略了。這就是所謂的異常屏蔽。由于異常信息的丟失,異常屏蔽可能會導致某些bug變得極其難以發現,程序員們不得不加班加點地找bug,如此毒瘤,怎能不除!幸好,為了解決這個問題,從Java 1.7開始,大佬們為Throwable類新增了addSuppressed方法,支持將一個異常附加到另一個異常身上,從而避免異常屏蔽。那么被屏蔽的異常信息會通過怎樣的格式輸出呢?我們再運行一遍剛才用try-with-resource包裹的main方法:

java.lang.Exception: send dataat basic.exception.Connection.sendData(Connection.java:5)at basic.exception.TryWithResource.main(TryWithResource.java:14)......Suppressed: basic.exception.MyException: closeat basic.exception.Connection.close(Connection.java:10)at basic.exception.TryWithResource.main(TryWithResource.java:15)... 5 more

可以看到,異常信息中多了一個Suppressed的提示,告訴我們這個異常其實由兩個異常組成,MyException是被Suppressed的異常??上部少R!

一個小問題

在使用try-with-resource的過程中,一定需要了解資源的close方法內部的實現邏輯。否則還是可能會導致資源泄露。

舉個例子,在Java BIO中采用了大量的裝飾器模式。當調用裝飾器的close方法時,本質上是調用了裝飾器內部包裹的流的close方法。比如:

public class TryWithResource { public static void main(String[] args) { try (FileInputStream fin = new FileInputStream(new File('input.txt'));GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(new File('out.txt')))) { byte[] buffer = new byte[4096]; int read; while ((read = fin.read(buffer)) != -1) {out.write(buffer, 0, read); } } catch (IOException e) { e.printStackTrace(); } }}

在上述代碼中,我們從FileInputStream中讀取字節,并且寫入到GZIPOutputStream中。GZIPOutputStream實際上是FileOutputStream的裝飾器。由于try-with-resource的特性,實際編譯之后的代碼會在后面帶上finally代碼塊,并且在里面調用fin.close()方法和out.close()方法。我們再來看GZIPOutputStream類的close方法:

public void close() throws IOException { if (!closed) { finish(); if (usesDefaultDeflater) def.end(); out.close(); closed = true; }}

我們可以看到,out變量實際上代表的是被裝飾的FileOutputStream類。在調用out變量的close方法之前,GZIPOutputStream還做了finish操作,該操作還會繼續往FileOutputStream中寫壓縮信息,此時如果出現異常,則會out.close()方法被略過,然而這個才是最底層的資源關閉方法。正確的做法是應該在try-with-resource中單獨聲明最底層的資源,保證對應的close方法一定能夠被調用。在剛才的例子中,我們需要單獨聲明每個FileInputStream以及FileOutputStream:

public class TryWithResource { public static void main(String[] args) { try (FileInputStream fin = new FileInputStream(new File('input.txt'));FileOutputStream fout = new FileOutputStream(new File('out.txt'));GZIPOutputStream out = new GZIPOutputStream(fout)) { byte[] buffer = new byte[4096]; int read; while ((read = fin.read(buffer)) != -1) {out.write(buffer, 0, read); } } catch (IOException e) { e.printStackTrace(); } }}

由于編譯器會自動生成fout.close()的代碼,這樣肯定能夠保證真正的流被關閉。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持好吧啦網。

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
九九99久久精品在免费线bt| 婷婷中文字幕一区| 亚洲性图久久| 韩国精品主播一区二区在线观看| 欧美亚洲综合视频| 国产调教精品| 久久精品国产一区二区| 免费视频一区二区三区在线观看| 国产精品男女| 精品久久国产一区| 91一区二区| 国产精品久久久久av电视剧| 欧美三区四区| 国产农村妇女精品一二区| 亚洲日韩视频| 精品一区视频| 99久久精品网| 偷拍亚洲精品| 国产 日韩 欧美 综合 一区| 精品一区二区男人吃奶| 日韩精品一区二区三区免费观影| 婷婷亚洲综合| 国产免费播放一区二区| 亚洲成人不卡| 日韩精品中文字幕一区二区| 国产精品二区不卡| 日韩影院免费视频| 国产videos久久| 日韩动漫一区| 久久中文字幕二区| 91成人精品在线| 亚洲成人二区| 欧美午夜三级| 99久久久久国产精品| 在线一区二区三区视频| 国产91在线精品| 亚洲精品欧美| 国产韩日影视精品| 麻豆久久久久久| aa国产精品| 亚洲女同av| 日韩高清欧美激情| 激情久久婷婷| 精品视频91| 日韩一区网站| 99在线精品免费视频九九视| 国产一区丝袜| 国产精品中文字幕亚洲欧美| 狠狠爱成人网| 久久精品亚洲一区二区| 伊人精品久久| 制服诱惑一区二区| 欧美~级网站不卡| 久久国产电影| 欧美日韩视频网站| 国产精品久久久久av蜜臀 | 国产一区二区三区自拍| 丰满少妇一区| 久久精品资源| 国产精品一区二区三区av麻| 久久国产88| 日韩精品一区第一页| 亚洲不卡av不卡一区二区| 日韩精品中文字幕第1页| 日本高清不卡一区二区三区视频 | 色爱综合网欧美| 日韩精品1区2区3区| 国产亚洲精品自拍| 视频一区日韩| 亚洲aa在线| 国产欧美丝祙| 老鸭窝一区二区久久精品| 麻豆成人在线观看| 国产成人免费精品| 久久影院资源站| 福利在线一区| 国产精品xx| 欧美日韩中文一区二区| 日韩中文欧美在线| 日韩1区2区日韩1区2区| 国产精品115| 日韩精品麻豆| 蜜桃av一区二区| 免费在线亚洲欧美| 性欧美xxxx免费岛国不卡电影| 欧美综合二区| 国产精选一区| 亚洲激情精品| 久久福利在线| 91久久久久| 国产精品极品| 欧美丰满日韩| 日韩精品电影一区亚洲| 色欧美自拍视频| 蜜臀久久久久久久| 国产a亚洲精品| 中文字幕免费精品| 人在线成免费视频| 日韩成人av影视| 日韩毛片在线| 老色鬼精品视频在线观看播放| 国产99久久| 精品视频免费| 欧美亚洲自偷自偷| 99成人在线| 久久久一本精品| 亚洲三级网址| 国产色综合网| 成人午夜精品| 久久精品一本| 国产美女精品视频免费播放软件| av一区二区高清| 免费在线小视频| 国产精品成人一区二区不卡| 国产亚洲字幕| 日韩成人午夜精品| 天堂va欧美ⅴa亚洲va一国产| 久久高清免费| 丝袜av一区| 日韩在线短视频| 国产suv精品一区二区四区视频 | 日韩精品中文字幕一区二区| 激情婷婷亚洲| 91精品一区国产高清在线gif| 另类小说一区二区三区| 国产精品一区二区免费福利视频| 蜜桃久久久久久| 午夜久久av | 99久久精品网站| 久久久噜噜噜| 日韩三区在线| 亚洲午夜精品久久久久久app| 99久久视频| 免费精品视频| 免费人成网站在线观看欧美高清| 亚洲天堂久久| 国产亚洲福利| 日韩欧美精品一区二区综合视频| 亚洲精品护士| 日韩欧美三区| 狂野欧美性猛交xxxx| 桃色av一区二区| 精品一区欧美| 中文字幕一区二区三区在线视频| 蜜臀av性久久久久蜜臀aⅴ四虎| 日韩av成人高清| 精品国产亚洲一区二区三区在线 | 亚洲精品在线观看91| 日本欧美在线| 成人一区而且| 一区三区视频| 欧美日韩一区二区三区在线电影| 蜜桃久久久久| 91精品在线观看国产| 中文不卡在线| 国产精品原创| 免费在线观看视频一区| 久久免费精品| 天堂av在线一区| 久久精品99国产精品日本| 国产精品99一区二区三| 爽好多水快深点欧美视频| 亚洲综合精品| 精品福利久久久| 免播放器亚洲| 正在播放日韩精品| 亚洲ab电影| 图片区亚洲欧美小说区| 国产欧美二区| 免费中文字幕日韩欧美| 美女毛片一区二区三区四区最新中文字幕亚洲 | 日韩1区在线| 欧美日本三区| 亚洲福利免费| 国产一二在线播放| 欧美自拍一区| 六月婷婷一区| 美女亚洲一区| 日韩电影在线视频| 麻豆成人av在线| 欧美亚洲tv| 日日夜夜免费精品视频| 尹人成人综合网| 人人精品亚洲| 91日韩在线| 国产欧洲在线| 久久久久久夜| 国产传媒在线| 国产偷自视频区视频一区二区| 欧美三级网址| 国产日韩亚洲欧美精品| 久久蜜桃精品| 另类中文字幕国产精品| 九九综合九九| 久久久国产精品网站| 69堂精品视频在线播放| 日韩精品一二区| 亚洲一区二区日韩| 亚洲精品麻豆| 日韩成人av影视|