天天看點

阿裡P8面試:微服務項目如何校驗參數(下)3 邊界檢查4 斷言5 總結

3 邊界檢查

在 Java 9 中,邊界檢查功能被添加到

java.util.Objects

。該功能由三個方法組成:

  • checkFromIndexSize
  • 阿裡P8面試:微服務項目如何校驗參數(下)3 邊界檢查4 斷言5 總結
  • checkFromToIndex
  • 阿裡P8面試:微服務項目如何校驗參數(下)3 邊界檢查4 斷言5 總結
  • checkIndex
  • 阿裡P8面試:微服務項目如何校驗參數(下)3 邊界檢查4 斷言5 總結
  • 該套工具不如判空方法靈活。它不允許自定義異常詳細資訊,僅适用于 List 和數組索引。它不處理封閉範圍(包含兩個端點)。

4 斷言

對于未暴露的方法,作為包作者,你應該控制方法在何時能被調用,是以你可以并且也應該確定隻傳入有效參數值。是以,非public方法可使用斷言檢查入參:

阿裡P8面試:微服務項目如何校驗參數(下)3 邊界檢查4 斷言5 總結

從本質上說,這些斷言是在聲稱被斷言的條件為 true,而不管用戶端如何調用。與普通校驗不同的是:

若斷言失敗,會抛 AssertionError

若斷言沒有作用,本質上不存在成本,除非通過将 -ea( 或 -enableassertion)辨別傳遞給 java 指令來啟用它們

尤其應檢查那些尚未由方法調用,而是存起供日後使用的參數的有效性。例如靜态工廠方法,它接受 int 數組并傳回數組的 List 視圖。若用戶端傳入 null,将抛 NullPointerException,因為該方法具有顯式檢查(調用 Objects.requireNonNull)。如果省略檢查,該将傳回對新建立的 List 執行個體的引用,該執行個體将在用戶端試圖使用它時抛出 NullPointerException。到那時,List 執行個體的起源很難确定,使調試變得複雜。

構造器就是一種特殊情況。務必檢查構造器入參有效性,避免構造生成執行個體對象時,違背對象的不變性。

在執行方法前,應顯式檢查參數,也有例外 - 有效性檢查成本較高或不切實際,或檢查在計算過程中隐式執行了。

例如,一個為對象 List 排序的方法,比如 Collections.sort(List)。List 中的所有對象必須互相比較。在對 List 排序的過程中,List 中的每個對象都會與清單中的其他對象進行比較。如果對象不能互相比較,将抛出 ClassCastException,這正是 sort 方法應該做的。是以,沒有必要預先檢查清單中的元素是否具有可比性。但不加差別地依賴隐式有效性檢查可能導緻失敗原子性的丢失。

有時,計算任務會隐式地執行所需的有效性檢查,但如果檢查失敗,則抛出錯誤的異常。即計算任務由于無效參數值所抛異常,與文檔中記錄的方法要抛出的異常不比對。此時應該使用異常轉換将計算任務抛出的異常轉換為正确的異常。

5 總結

請勿覺得對參數的任意限制都是好事,而應把方法設計得既通用又實用。

對參數施加的限制越少越好,假設該方法可對它所接受的所有參數值進行合理的處理。然而,一些限制常常是實作抽象的内在限制。

每次編寫方法或構造器時,都應考慮參數存在哪些限制。你應該在文檔中記錄這些限制,并在方法主體的開頭顯式檢查。養成這樣的習慣!這一少量工作将在有效性檢查出現第一次失敗時連本帶利地償還給你!