Java-try-with-resource

Java-try-with-resource

Java語言在發展至SE7時加進了try-with-resource的語法,只要「Resource」實作過java.lang.AutoCloseable這個介面,
在撰寫程式碼時可以讓整個例外處理的結構變得比較簡潔。

未使用try-with-resouce

1
2
3
4
5
6
7
8
9
10
11
12
// resource 宣告
Resource res = null;
try {
res = new Resource(); // resource 初始化
// 其他處理
}
catch (Exception ex) {
// 例外處理
}
finally {
// resource 釋放或清除
}

使用try-with-resouce

1
2
3
4
5
6
7
8
9
10
11
12
// 於 try 關鍵字後的小括號中進行 resource 宣告及初始化
try (Resource res = new Resource()) {
// 其他處理
// 在 try 後方小括號初始化的資源會在離開 try 區塊時自動呼叫 close()
}
catch (Exception ex) {
// 例外處理
}

不過上方結構有些限制,如果需要在catch區塊中存取Resource的變數的話,
只能回到之前不使用try-with-resouce的結構來進行,因為try-with-resource要求
需要被自動呼叫close方法的物件一定要在try後方的小括號中宣告及初始化,否則會引發編譯時期錯誤。

SE9使用try-with-resouce

1
2
3
4
5
6
7
8
9
10
11
12
在Java SE9之後針對這個限制進行了一些改變,允許開發者如同未使用try-with-resource一樣
在進入try區塊前先完成宣告及初始化,try之後的小括號中只要列出需要被自動呼叫close方法的變數即可。

// resource 宣告
Resource res = new Resource();
try (res) {
// 其他處理
// 在 try 後方小括號的資源會在離開 try 區塊時自動呼叫 close()
}
catch (Exception ex) {
// 例外處理
}

實際應用

1
2
3
4
5
6
7
8
try (StringWriter out = new StringWriter();
JsonGenerator jGenerator = JSONUtils.getFactory().createGenerator(out)) {
jGenerator.writeStartObject();
jGenerator.writeStringField("David", "Chen");
jGenerator.writeEndObject();
jGenerator.flush();
return out.toString();
}

結論

1
2
這邊要注意的是,不管是哪個版本的try-with-resource結構,其中的resource如果沒有宣告為final變數的話,
也都會被視作是「effectively final(等效final)變數」,也就是不能在其有效範圍中進行變數異動。