Kotlin & Checked Exception
Checked Exception in Java and Kotlin
最近將JSONObject
相關的代碼copy到Kotlin檔案時,下意識的讓Android Studio幫我將Java語法直接轉譯成Kotlin語法,結果發現,在Java中調用JSONObject
的put()
方法時,一般來說都需要額外使用try-catch包裝起來,否則compiler會在旁邊一直吵你,不讓你通過編譯:
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("key","value");
} catch (JSONException e) {
e.printStackTrace();
}
但在Kotlin中,是不需要的
val jsonObject = JSONObject()
jsonObject.put("key", "value")
Kotlin竟然不需要去做try-catch的動作?這真是太神奇了!
在好奇心的驅使之下,到Kotlin的官方網站找尋答案,發現原來是因為Kotlin本身不支援Checked Exceptions,所以就算當一段code裡面會拋出Checked Exception,在編譯的時候都會直接通過,只有在執行的時候才會崩潰並發現。
一些有趣的事
對於Kotlin的這個特性,感覺上大家討論得還滿激烈的XD,光是中文的部分,有人批評,也有人看不下去這個批評予以反擊。
我個人的看法也是比較支持Kotlin的做法,認為使用過多的Checked Exception是沒有意義的,同時造成了可讀性與dependency上的困擾。
而在實際應用上,我認爲在Exception handling這塊,RxJava就做得很棒,以RxJava2的Completable
為例:
Completable.fromAction {
// do your stuff
}.subscribe({
// onComplete
}, {
// onError
})
我們寫的code就是應該專注於我們要解決的問題,例外處理的部份畢竟是「例外」,例外不就是十分之一、千分之一,或是「萬一」才會發生的事嗎?所以就應該可以在另外一個地方handle掉這些事情。
public final class CompletableFromAction extends Completable { final Action run; public CompletableFromAction(Action run) {
this.run = run;
} @Override
protected void subscribeActual(CompletableObserver s) {
Disposable d = Disposables.empty();
s.onSubscribe(d);
try {
run.run();
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
if (!d.isDisposed()) {
s.onError(e);
}
return;
}
if (!d.isDisposed()) {
s.onComplete();
}
}}
像CompletableFromAction
這個實作,就是catch了所有的Throwable
,統一將例外事件導到onError()
再進行處理。像這樣的處理機制,分離了正常與異常狀況下的邏輯,我認為相當的優美,我實在是無法理解為何反對派反對直接catch Exception/Throwable的想法呀~
再者,Kotlin畢竟是新語言,也汲取了在Java中相當多的經驗與教訓;我認為Kotlin的其中一個核心設計精神,就是能將錯誤檢查從執行期提前到編譯期(對我就是在說那些驚嘆號問號null什麼的)。對於Exception這個部分,Kotlin也導入了Nothing
,用來輔助在編譯期判斷當錯誤發生時,你的程式還能繼續執行嗎?(詳情請見之前的文章:Kotlin使用心得(二):Any與Nothing間的奇妙關係、以及與Java中Void的愛恨情仇)
最後,我覺得如果出現一個Exception就導致整個程式邏輯都炸了…那其實再多的Checked Exception也沒用吧(聳肩)