1. 程式人生 > >第五十七條 只針對異常的情況才使用異常

第五十七條 只針對異常的情況才使用異常

異常,是java中不可繞過的一部分。善用異常,可以大大提高效率。但如果有一天,一不小心,遇到下面的程式碼

        try {
            int i = 0;
            while (true){
                range[i++].climb();
            }
        }catch (ArrayIndexOutOfBoundsException e){

        }

這段程式碼有什麼用呢?我們仔細看了看,發現原來是要遍歷陣列元素,然後呼叫每個元素的 climb() 方法,但這個設計有點費解,並且不太符合常理。這段程式碼明顯是想讓陣列一致遍歷,直到邊界,繼續遍歷,然後陣列越界,此時被異常捕獲,遍歷終止。雖然也能達到目的,但這麼做很容易引起人誤解,並且方法也不規範,我們完全可以使用for迴圈來處理。

    for(ang m : range){
            m.climb();
        }

下面程式碼比著上面,有以下幾個好處,一、異常機制是針對不正常的情景,jvm很少對它們進行優化;二、把程式碼放到try catch 中可能會阻止了jvm的部分優化;三、對陣列遍歷的標準模式效能很高,不用做無謂功。事實上,基於異常模式比標準模式要慢的多。隨意使用異常,不僅模糊了程式碼的意圖,減低了效率,甚至還可能隱藏真正的bug,比說說某些程式碼中,如果有元素為null,還呼叫物件的方法,則會報空指標,本應該判斷,進行分流;但如果加入異常,則會隱藏了這部分邏輯。使用了異常,就應該當產生了與這個bug的異常時,會被捕捉到,然後迴圈終止,這才是異常的用法。

如果我們設計api時,良好的習慣是對外暴露方法,而非使用異常。
一、狀態測試,提供是否可以呼叫這個狀態的方法。例如:迭代器裡,如果只有一個 next()方法提供下一個元素,但沒有提供檢測是否還有下一個元素,我們就只能通過元素個數或異常來終止遍歷,如果提供了方法,則

        for (Iterator<String> i = collection.iterator(); i.hasNext(); ) {
            String s = i.next();
        }
 
這樣,我們不用藉助異常和輔助條件,只用自己的條件,就可以完美的實現功能。
二、 當狀態方法被呼叫,返回值時,返回可識別的值,比如 null。我們不清楚外面的業務邏輯,所以將內部邏輯控制好,將資料暴露給外面,讓使用者根據業務邏輯,進行自己的邏輯判斷,完成功能。

異常是為了在異常情況下使用而設計的,不是為了普通控制使用的,切記。