Assert使用場景
Web 應用在接受表單送出的資料後都需要對其進行合法性檢查,如果表單資料不合法,請求将被駁回。類似的,當我們在編寫類的方法時,也常常需要對方法入參進行合 法性檢查,如果入參不符合要求,方法将通過抛出異常的方式拒絕後續處理。舉一個例子:有一個根據檔案名擷取輸入流的方法:InputStream getData(String file),為了使方法能夠成功執行,必須保證 file 入參不能為 null 或空白字元,否則根本無須進行後繼的處理。這時方法的編寫者通常會在方法體的最前面編寫一段對入參進行檢測的代碼,如下所示:
Spring Assert類幫助我們校驗參數。通過使用Assert類方法,我們可以寫出我們認為是正确的假設,反之,會抛出運作時異常。
public InputStream getData(String file) {
if (file == null || file.length() == 0|| file.replaceAll("\\s", "").length() == 0) {
throw new IllegalArgumentException("file入參不是有效的檔案位址");
}
…
}
類似以上檢測方法入參的代碼是非常常見,但是在每個方法中都使用手工編寫檢測邏輯的方式并不是一個好主意。閱讀 Spring 源碼,您會發現 Spring 采用一個 org.springframework.util.Assert 通用類完成這一任務。
Assert類目的
每個Assert的方法可以與java assert表達式進行比較。java assert表達式在運作時如果條件校驗失敗,則抛出Error,有趣的是,這些斷言可以被禁用。
Spring Assert的方法有一些特點:
- 都是static方法
- 抛出IllegalArgumentException 或 IllegalStateException異常
- 第一個參數通常是需驗證的對象或邏輯條件
- 最後參數通常是異常消息,用于驗證失敗時顯示
- 消息可以作為String參數或Supplier 參數傳輸
盡管Spring Assert與其他架構的名稱類似,如JUnit或其他架構,但其實沒有任何共同之處。Spring Assert不是為了測試,而是為了調試。
使用示例
讓我們定義Car類,并有public方法drive():
public class Car {
private String state = "stop";
public void drive(int speed) {
Assert.isTrue(speed > 0, "speed must be positive");
this.state = "drive";
// ...
}
}
我們看到speed必須是正數,上面一行簡短的代碼用于檢測條件,如果失敗抛出異常:
if (!(speed > 0)) {
throw new IllegalArgumentException("speed must be positive");
}
每個Assert的方法包含大概類似上面的條件代碼塊,校驗失敗抛出運作時異常,應用程式不期望恢複。
如果我們嘗試帶負數參數調用drive方法,會抛出IllegalArgumentException異常:
Exception in thread “main” java.lang.IllegalArgumentException: speed must be positive
邏輯斷言
- isTrue()
上面已經看到示例,其接受布爾條件,如果條件為假抛出IllegalArgumentException 異常。
- state()
該方法與isTrue一樣,但抛出IllegalStateException異常。
如名稱所示,通常用在因對象的非法狀态時,方法不能繼續執行。假設騎車運作是不能加油,我們可以使用state方法斷言:
public void fuel() {
Assert.state(this.state.equals("stop"), "car must be stopped");
// ...
}
當然,我們能使用邏輯斷言驗證所有場景。但為了更好的可讀性,我們可以使用其他的斷言,使代碼表達性更好。
對象和類型斷言
- notNull()
通過notNull()方法可以假設對象不null:
public void сhangeOil(String oil) {
Assert.notNull(oil, "oil mustn't be null");
// ...
}
- isNull()
另外一方面,我們能使用isNull()方法檢查對象為null:
public void replaceBattery(CarBattery carBattery) {
Assert.isNull(
carBattery.getCharge(),
"to replace battery the charge must be null");
// ...
}
- isInstanceOf()
使用isInstanceOf()方法檢查對象必須為另一個特定類型的執行個體:
public void сhangeEngine(Engine engine) {
Assert.isInstanceOf(ToyotaEngine.class, engine);
// ...
}
示例中,ToyotaEngine 是類 Engine的子類,是以檢查通過.
- isAssignable()
使用Assert.isAssignable()方法檢查類型:
public void repairEngine(Engine engine) {
Assert.isAssignable(Engine.class, ToyotaEngine.class);
// ...
}
這兩個斷言代表 is-a 關系.
文本斷言
通常用來檢查字元串參數。
- hasLength()
如果檢查字元串不是空符串,意味着至少包含一個空白,可以使用hasLength()方法:
public void startWithHasLength(String key) {
Assert.hasLength(key, "key must not be null and must not the empty");
// ...
}
- hasText()
我們能增強檢查條件,字元串至少包含一個非空白字元,可以使用hasText()方法:
public void startWithHasText(String key) {
Assert.hasText(
key,
"key must not be null and must contain at least one non-whitespace character");
// ...
}
- doesNotContain()
我們能通過doesNotContain()方法檢查參數不包含特定子串:
public void startWithNotContain(String key) {
Assert.doesNotContain(key, "123", "key mustn't contain 123");
// ...
}
Collection和map斷言
- Collection應用notEmpty()
如其名稱所示,notEmpty()方法斷言collection不空,意味着不是null并包含至少一個元素:
public void repair(Collection<String> repairParts) {
Assert.notEmpty(
repairParts,
"collection of repairParts mustn't be empty");
// ...
}
- map應用notEmpty()
同樣的方法重載用于map,檢查map不null,并至少包含一個entry(key,value鍵值對):
public void repair(Map<String, String> repairParts) {
Assert.notEmpty(
repairParts,
"map of repairParts mustn't be empty");
// ...
}
數組斷言
- notEmpty()
notEmpty()方法可以檢查數組不null,且至少包括一個元素:
public void repair(String[] repairParts) {
Assert.notEmpty(
repairParts,
"array of repairParts mustn't be empty");
// ...
}
- noNullElements()
noNullElements()方法確定數組不包含null元素:
public void repairWithNoNull(String[] repairParts) {
Assert.noNullElements(
repairParts,
"array of repairParts mustn't contain null elements");
// ...
}
注意,如果數組為空檢查可以通過,隻要沒有null元素。
總結
我們浏覽Assert類,在spring架構中應用廣泛,充分利用它可以很容易寫出強壯的代碼。