2009-11-27 50 views
5

這裏是實現這一目標的典型方式:我覺得這個解決方案是醜陋的如何在我的方法輸入參數上放置驗證約束?

public void myContractualMethod(final String x, final Set<String> y) { 
    if ((x == null) || (x.isEmpty())) { 
     throw new IllegalArgumentException("x cannot be null or empty"); 
    } 
    if (y == null) { 
     throw new IllegalArgumentException("y cannot be null"); 
    } 
    // Now I can actually start writing purposeful 
    // code to accomplish the goal of this method 

。您的方法會快速填寫樣板代碼,檢查有效的輸入參數合約,從而模糊了方法的核心。

這裏想什麼,我有:

public void myContractualMethod(@NotNull @NotEmpty final String x, @NotNull final Set<String> y) { 
    // Now I have a clean method body that isn't obscured by 
    // contract checking 

如果這些標註看起來像JSR 303/Bean驗證規格,那是因爲我借了他們。不幸的是,他們似乎並不這樣工作;它們用於註釋實例變量,然後通過驗證器運行對象。

哪個many Java design-by-contract frameworks提供了最接近我的「喜歡有」的例子?拋出的異常應該是運行時異常(如IllegalArgumentExceptions),因此封裝不會被破壞。

回答

5

如果您正在尋找一個完善的設計承包機制,我會看看Wikipedia page for DBC上列出的一些項目。

但是,如果您尋找更簡單的東西,則可以查看google collection中的Preconditions類,該類提供了checkNotNull()方法。所以,你可以重寫你發佈到代碼:

public void myContractualMethod(final String x, final Set<String> y) { 
    checkNotNull(x); 
    checkArgument(!x.isEmpty()); 
    checkNotNull(y); 
} 
+0

Preconditions.checkArgument(!x.isEmpty())。 – 2009-11-27 16:57:36

+1

啊哈,總是有幫助圖書館的創造者在手:) – 2009-11-27 22:14:22

0

這並不直接回答你的問題,但我覺得你的問題的一部分是,你矯枉過正驗證。舉例來說,你可以替換爲第一個測試:

if (x.isEmpty()) { 
    throw new IllegalArgumentException("x cannot be empty"); 
} 

,並依賴於Java拋出一個NullPointerException如果xnull。你只需要改變你的「合同」,說NPE是針對某些類型的「你給我打了非法參數」的情況。

0

Jared指出了各種爲DBC增加了對Java的支持的框架。
我發現最好的工作是:簡單地在JavaDoc中記錄你的合同(或者你使用的任何Documentationframework; Doxygen支持DBC標籤)
讓你的代碼被大量的拋出和你的參數檢查混淆isn'對你的讀者真的很有幫助。文檔是。

+1

問題是當你忽略,或者如果你錯過了其中一個前提條件,那麼它們不能保證你會得到什麼樣的行爲。最好你可能會得到一個NPE,最糟糕的情況是,最終會出現一些隨機異常,但不知道爲什麼會發生。 – 2009-11-27 16:08:47

+0

@Jared我同意。但通常沒有更好的辦法。無論是你帶來一個沉重的框架,並把所有的學習和混淆開銷或你堅持下去。如果你真的想使用DBC,你最好用本地語言來支持它。 – pmr 2009-11-27 19:10:56

2

我見過的技術大致如下:Eric Burke。這是靜態導入的優雅使用。代碼讀得非常好。

爲了得到這個想法,這裏是Contract類。這裏很少,但可以根據需要輕鬆填寫。

package net.codetojoy; 

public class Contract { 
    public static void isNotNull(Object obj) { 
     if (obj == null) throw new IllegalArgumentException("illegal null"); 
    } 
    public static void isNotEmpty(String s) { 
     if (s.isEmpty()) throw new IllegalArgumentException("illegal empty string"); 
    } 
} 

這裏是一個示例用法。該foo()方法說明了靜態導入:

package net.codetojoy; 

import static net.codetojoy.Contract.*; 

public class Example { 
    public void foo(String str) { 
     isNotNull(str); 
     isNotEmpty(str); 
     System.out.println("this is the string: " + str); 
    } 

    public static void main(String[] args) { 
     Example ex = new Example(); 
     ex.foo(""); 
    } 
} 

注:實驗時,注意周圍there may be a bug做這個默認的包中。我肯定失去了腦細胞。

+1

我忘了提到拋出一個IllegalArg異常與一個NullPointer存在一個微妙的優勢。就前者而言,API作者明確告訴你關於合同的一些事情。 (即,你還在想知道你是否正在處理一個bug。) – 2009-11-27 16:19:38

0

我會使用Parameter Annotations,Reflection和一個通用的驗證器類來創建一個應用程序範圍的工具。例如,可以編寫一個類方法,如:

.. myMethod的(@NotNull串x,@notNullorZero y字符串){

if (Validator.ifNotContractual(getParamDetails()) { 
    raiseException.. 
    or 
    return .. 
} 

}

類方法 「標記的」來說明他們的合同要求。使用反射來自動發現參數,它們的值和註釋。將它全部發送到靜態類來驗證並讓您知道結果。

1

有一個小的Java Argument Validation包,實現爲Plain Java。它帶有幾個標準檢查/驗證。對於那些需要自己更具體的驗證的情況,它帶有一些輔助方法。對於多次發生的驗證,只需使用您自己的接口來擴展接口ArgumentValidation並創建從類ArgumentValidationImpl擴展的實現類。

+0

它帶有幾個例子,讓你走。 http://java-arg-val.sourceforge.net/usage.html (本頁面爲2個示例,Java Doc爲3個(在給定頁面上引用它們) – Verhagen 2010-01-28 22:14:10

0

不是完全可行的解決方案,但JSR-303的建議爲method-level validation extension。因爲這只是一個擴展提議,所以JSR-303的實現可以自由地忽略它。找到一個實現有點棘手。我不認爲Hibernate Validator支持它,但我認爲agimatec-validation有實驗支持。我還沒有用於這個目的,所以我不知道他們的工作效果如何。不過,如果有人放棄它,我會很感興趣。