Effective Java 讀書筆記——38:檢查引數的有效性
阿新 • • 發佈:2019-01-22
一般在方法執行之前先檢查引數的有效性,如果引數值無效,那麼很快它就會失敗,並且清楚的丟擲合適的異常。
如果這個方法沒有檢查引數的異常,那麼可能在方法處理中出現令人費解的異常。更糟糕的有可能是,方法可以正常返回,但是卻使得某個物件處於被破壞的狀態.
丟擲異常
對於公有方法,可以在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在後面的程式中可能會非常難以定位。因此,構造器檢查引數的有效性是非常重要的,必須保證構造出來的物件是有效的。