SpringBoot內置工具類之 斷言 Assert

說到斷言Assert,我們在查看源碼時經常看到,它是使用比較頻繁的一個工具類,但我也經常忽略它的存在。現在就讓我們一起看看它吧!

About斷言Assert

  1. 斷言是一個判斷邏輯,用來檢查不該發生的情況;
  2. 斷言的判定規則:
    2.1.值爲true時,程序從斷言語句處繼續執行;
    2.2.值爲false時,程序從斷言語句處拋出異常,停止執行;
    3.早在JDK的1.4版本已經引入斷言assert,通過命令-enableassertions開啓,通過命令-disableassertions關閉;不加參數,全局生效;加了參數,只在某個類中使用;具體可通過java help命令查看;
  3. Springframework框架中也提供了斷言工具類Assert,通常用於數據合法性驗證。我們今天說的就是它。

斷言Assert工具類的使用

public static void main(String[] argo){
    
    Object obj = null;
    
    Assert.isNull(obj, "對象必須爲NULL,否則拋異常不予放行");
    
    Assert.notNull(new Object(), "對象不能爲NULL,否則拋異常不予放行");
    
    Assert.state(true, "參數必須爲true,否則拋異常不予放行");
    
    Assert.isTrue(true, "參數必須爲true,否則拋異常不予放行");
    
    // null 或 空字符串 斷言失敗,空格斷言成功
    Assert.hasLength(" ", "參數必須有長度,否則拋異常不予放行");
    // null、空字符串、純空格斷言失敗
    Assert.hasText("  dd", "參數必須有正文,否則拋異常不予放行");
    
    Assert.doesNotContain("text", "bb", "第一個參數不能包含第二個參數,否則拋異常不予放行");
    
    Object[] objArray = {true, false,};
    // 除了對象數組,還有其他類型的數組,在此不在一一舉例
    Assert.notEmpty(objArray, "對象數組不能爲空,否則拋異常不予放行");
    
    Assert.noNullElements(objArray, "對象數組中不能有null元素,否則拋異常不予放行");
    
    Map<String,String> map = new HashMap<String,String>();
    
    Assert.isInstanceOf(Map.class, map, "第二個參數必須是第一個參數的實例,否則拋異常不予放行");
    
    Assert.isAssignable(Map.class, List.class, "第二個參數必須是第一個參數的子類或者實現類,否則拋異常不予放行");    
    
    System.out.println("全部斷言成功~!");
  }

把最後一個斷言設置失敗時,失敗的語句處拋出異常,程序在此處終止運行,運行結果如下所示:

Exception in thread "main" java.lang.IllegalArgumentException: 第二個參數必須是第一個參數的子類或者實現類,否則拋異常不予放行: interface java.util.List
  at org.springframework.util.Assert.assignableCheckFailed(Assert.java:720)
  at org.springframework.util.Assert.isAssignable(Assert.java:651)
  at com.example.util.SpringUtilTest.main(SpringUtilTest.java:40)

一起看下 Assert工具類的部分源碼

import java.util.Collection;
import java.util.Map;
import java.util.function.Supplier;

import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

/**
 * 斷言工具類類
 * SpringBoot 2.1.4.RELEASE
 * 符合條件就繼續執行,否則拋異常不予放行
 */
public abstract class Assert {

  /**
   * 參數expression必須爲true,否則拋異常,不予放行
   * @param expression boolean型表達式
   * @param message 用於定製異常消息內容
   */
  public static void state(boolean expression, String message) {
    if (!expression) {
      throw new IllegalStateException(message);
    }
  }

  /**
   * 參數expression必須爲true,否則拋異常,不予放行
   * @param expression
   * @param message
   */
  public static void isTrue(boolean expression, String message) {
    if (!expression) {
      throw new IllegalArgumentException(message);
    }
  }

  /**
   * 要求對象object必須爲null,否則拋異常,不予放行
   * @param object
   * @param message
   */
  public static void isNull(@Nullable Object object, String message) {
    if (object != null) {
      throw new IllegalArgumentException(message);
    }
  }
  
  /**
   * 要求參數object不爲null,否則拋異常,不予放行;
   * 和isNull() 方法相反
   * @param object
   * @param message
   */
  public static void notNull(@Nullable Object object, String message) {
    if (object == null) {
      throw new IllegalArgumentException(message);
    }
  }

  /**
   * 要求參數text必須有長度,不爲null且長度大於0,否則拋異常,不予放行
   * @param text 字符串文本
   * @param message
   */
  public static void hasLength(@Nullable String text, String message) {
    if (!StringUtils.hasLength(text)) {
      throw new IllegalArgumentException(message);
    }
  }

  /**
   * 要求參數text必須有內容,否則拋異常,不予放行
   * @param text 字符串文本
   * @param message
   */
  public static void hasText(@Nullable String text, String message) {
    if (!StringUtils.hasText(text)) {
      throw new IllegalArgumentException(message);
    }
  }

  /**
   * 要求textToSearch不包含substring,否則拋異常,不予放行
   * @param textToSearch 要檢索的字符串文本
   * @param substring 被檢索字符
   * @param message
   */
  public static void doesNotContain(@Nullable String textToSearch, String substring, String message) {
    if (StringUtils.hasLength(textToSearch) && StringUtils.hasLength(substring) &&
        textToSearch.contains(substring)) {
      throw new IllegalArgumentException(message);
    }
  }

  /**
   * 要求參數array不爲null,否則拋異常,不予放行
   * @param array 對象數組
   * @param message
   */
  public static void notEmpty(@Nullable Object[] array, String message) {
    if (ObjectUtils.isEmpty(array)) {
      throw new IllegalArgumentException(message);
    }
  }
  
  /**
   * 要求對象數組array中沒有Null元素,否則拋異常,不予放行
   * @param array
   * @param message
   */
  public static void noNullElements(@Nullable Object[] array, String message) {
    if (array != null) {
      for (Object element : array) {
        if (element == null) {
          throw new IllegalArgumentException(message);
        }
      }
    }
  }
  
  /**
   * 要求集合collection不爲null、不爲空集合,否則拋異常,不予放行
   * @param collection
   * @param message
   */
  public static void notEmpty(@Nullable Collection<?> collection, String message) {
    if (CollectionUtils.isEmpty(collection)) {
      throw new IllegalArgumentException(message);
    }
  }

  /**
   * 要求Map集合不爲null,不爲空集合,否則拋異常,不予放行
   * @param map the map to check
   * @param message the exception message to use if the assertion fails
   * @throws IllegalArgumentException if the map is {@code null} or contains no entries
   */
  public static void notEmpty(@Nullable Map<?, ?> map, String message) {
    if (CollectionUtils.isEmpty(map)) {
      throw new IllegalArgumentException(message);
    }
  }
  
  /**
   * 要求對象obj必須是指定類type的實例,否則拋異常,不予放行
   * @param type
   * @param obj
   * @param message
   */
  public static void isInstanceOf(Class<?> type, @Nullable Object obj, String message) {
    notNull(type, "Type to check against must not be null");
    if (!type.isInstance(obj)) {
      instanceCheckFailed(type, obj, message);
    }
  }

  /**
   * 要求對象obj必須是指定類type的實例,否則拋異常,不予放行
   * @param type 
   * @param obj
   * @param message
   */
  public static void isInstanceOf(Class<?> type, @Nullable Object obj) {
    isInstanceOf(type, obj, "");
  }

  /**
   * 要求參數subType必須是參數superType的子類或者實現類,否則拋出異常,不予放行
   * @param superType
   * @param subType
   * @param message
   */
  public static void isAssignable(Class<?> superType, @Nullable Class<?> subType, String message) {
    notNull(superType, "Super type to check against must not be null");
    if (subType == null || !superType.isAssignableFrom(subType)) {
      assignableCheckFailed(superType, subType, message);
    }
  }

  /**
   * 要求參數subType必須是參數superType的子類或者實現類,否則拋出異常,不予放行
   * @param superType
   * @param subType
   * @param message
   */
  public static void isAssignable(Class<?> superType, Class<?> subType) {
    isAssignable(superType, subType, "");
  }
  
  private static void instanceCheckFailed(Class<?> type, @Nullable Object obj, @Nullable String msg) {
    String className = (obj != null ? obj.getClass().getName() : "null");
    String result = "";
    boolean defaultMessage = true;
    if (StringUtils.hasLength(msg)) {
      if (endsWithSeparator(msg)) {
        result = msg + " ";
      }
      else {
        result = messageWithTypeName(msg, className);
        defaultMessage = false;
      }
    }
    if (defaultMessage) {
      result = result + ("Object of class [" + className + "] must be an instance of " + type);
    }
    throw new IllegalArgumentException(result);
  }

  private static void assignableCheckFailed(Class<?> superType, @Nullable Class<?> subType, @Nullable String msg) {
    String result = "";
    boolean defaultMessage = true;
    if (StringUtils.hasLength(msg)) {
      if (endsWithSeparator(msg)) {
        result = msg + " ";
      }
      else {
        result = messageWithTypeName(msg, subType);
        defaultMessage = false;
      }
    }
    if (defaultMessage) {
      result = result + (subType + " is not assignable to " + superType);
    }
    throw new IllegalArgumentException(result);
  }

  private static boolean endsWithSeparator(String msg) {
    return (msg.endsWith(":") || msg.endsWith(";") || msg.endsWith(",") || msg.endsWith("."));
  }

  private static String messageWithTypeName(String msg, @Nullable Object typeName) {
    return msg + (msg.endsWith(" ") ? "" : ": ") + typeName;
  }

  @Nullable
  private static String nullSafeGet(@Nullable Supplier<String> messageSupplier) {
    return (messageSupplier != null ? messageSupplier.get() : null);
  }
}

源碼看後,好像並沒有什麼特別之處,驗證失敗就拋出異常,終止代碼的執行。

最後總結

Assert工具類中大約有30多個靜態方法供外部類調用,它的特點就是符合條件繼續執行,否則拋出IllegalArgumentException異常。這個工具類是Spring框架util包(org.springframework.util)中的工具類,把這個工具類看過一遍以後,你有什麼啓發嗎?

突然想重寫Service,來一個優雅的異常處理。

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