Effective Java 讀書筆記——38:檢查參數的有效性

一般在方法執行之前先檢查參數的有效性,如果參數值無效,那麼很快它就會失敗,並且清楚的拋出合適的異常。

如果這個方法沒有檢查參數的異常,那麼可能在方法處理中出現令人費解的異常。更糟糕的有可能是,方法可以正常返回,但是卻使得某個對象處於被破壞的狀態.

拋出異常

對於公有方法,可以在Javadoc中的@throw標籤來說明違反異常時所拋出的異常類型。一旦在文檔中說明了異常,那麼強加這些類型的異常檢測就會是比較容易的事情,例子如下:

    // Modular Arithmetic Operations

    /**
     * Returns a BigInteger whose value is {@code (this mod m}).  This method
     * differs from {@code remainder} in that it always returns a
     * <i>non-negative</i> BigInteger.
     *
     * @param  m the modulus.
     * @return {@code this mod m}
     * @throws ArithmeticException {@code m} ≤ 0
     * @see    #remainder
     */
    public BigInteger mod(BigInteger m) {
        if (m.signum <= 0)
            throw new ArithmeticException("BigInteger: modulus not positive");

        BigInteger result = this.remainder(m);
        return (result.signum >= 0 ? result : result.add(m));
    }

上面這個例子是BigInteger中的求模方法,取模的時候需要其大於0,否則拋出異常。

斷言

另外,對於未被導出的方法,作爲包的創建者,你可以控制這個方法在哪些情況下可以被調用,因此你可以,也應該確保只將有效的參數傳遞進去。因此,非公有方法通常應該使用斷言(assert)來檢查它們的參數,如下:

	private static void sort(long a[], int offset, int length) {
		assert a != null;
		assert offset >= 0 && offset <= a.length;
		assert length >= 0 && length <= a.length - offset;
	}

在生產環境中,一般是不支持assert的,因此這樣可以提高效率,沒有成本開銷。所以,assert只在私有方法中使用,因爲私有方法的調用者開發者,他和被調用者之間是一種弱契約關係,或者說沒有契約關係,其間的約束是依靠開發者自己控制的,開發者應該有充分的理由相信自己傳入的參數是有效的。所以,從某種角度上來說,assert只是起到一個預防開發者自己出錯,或者是程序的無意出錯。

另外

有一些參數暫時沒有直接用到,只是保存起來供以後使用,這種參數的有效性檢查也是尤其重要:
    static List<Integer> intArrayAsList(final int[] a) {
        if (a == null)
            throw new NullPointerException();

        return new AbstractList<Integer>() {
            public Integer get(int i) {
                return a[i];  // Autoboxing (Item 5)
            }

            @Override public Integer set(int i, Integer val) {
                int oldVal = a[i];
                a[i] = val;     // Auto-unboxing
                return oldVal;  // Autoboxing
            }

            public int size() {
                return a.length;
            }
        };
    }

在上面的例子,傳入的是一個int數組,返回的是它的list視圖。如果傳入的是null,返回了一個新建的list,然後錯誤的null在後面的程序中可能會非常難以定位。因此,構造器檢查參數的有效性是非常重要的,必須保證構造出來的對象是有效的。

例外

儘管在構造器中檢查參數的有效性非常必要,但是也有例外,可能在有效情況下檢查參數的有效性是及其昂貴的,甚至是不切實際的。比如說,Collections.sort(list)。列表中的所有對象都是可以比較的。在排序過程中會自動檢查這些參數的有效性,而並不是在構造的時候檢查參數的有效性。

總結

並非對參數的任何限制都是好事,一般來說要儘可能的通用, 符合實際的需要。假如方法對它能接受的參數都能完成合理的計算,那麼對於參數的限制其實是越少越好的。因此,鼓勵開發者把限制寫到文檔中,並在方法的開頭顯式的檢查參數的有效性。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章