• SpringBoot内置工具类之断言Assert的使用与部分解析


    2023.10.29更新:

    使用assert的不利之处:

    1、assert关键字需要在运行时候显式开启才能生效,否则你的断言就没有任何意义。而现在主流的Java IDE工具默认都没有开启-ea断言检查功能。这就意味着你如果使用IDE工具编码,调试运行时候会有一定的麻烦。并且,对于Java Web应用,程序代码都是部署在容器里面,你没法直接去控制程序的运行,如果一定要开启-ea的开关,则需要更改Web容器的运行配置参数。这对程序的移植和部署都带来很大的不便。

    2、用assert代替if是陷阱之二。assert的判断和if语句差不多,但两者的作用有着本质的区别:assert关键字本意上是为测试调试程序时使用的,但如果不小心用assert来控制了程序的业务流程,那在测试调试结束后去掉assert关键字就意味着修改了程序的正常的逻辑。

    3、assert断言失败将面临程序的退出。这在一个生产环境下的应用是绝不能容忍的。一般都是通过异常处理来解决程序中潜在的错误。但是使用断言就很危险,一旦失败系统就挂了。

    因此, 应当避免在Java中使用assert关键字,除非哪一天Java默认支持开启-ea的开关,这时候可以考虑。对比一下,assert能给你带来多少好处,多少麻烦,这是我们选择是否使用的的原则。


    前言

    先例举一个service的demo中用来验证参数对象的封装方法,使用了Assert工具类后是不是比普通的 if(xxx) { throw new RuntimeException(msg) } 看上去要简洁多了?
    在这里插入图片描述

    断言Assert工具类简介

    1. 断言是一个判断逻辑,用来检查不该发生的情况;
    2. 断言的判定规则:
      2.1.值为true时,程序从断言语句处继续执行;
      2.2.值为false时,程序从断言语句处抛出异常,停止执行;
      2.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("全部断言成功~!");
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    把最后一个断言设置失败时,失败的语句处抛出异常,程序在此处终止运行,运行结果如下所示:

    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)
    
    • 1
    • 2
    • 3
    • 4

    断言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);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241

    简单来说就是验证失败就抛出异常,终止代码的执行。


    总结

    Assert工具类中大约有30多个静态方法供外部类调用,它的特点就是符合条件继续执行,否则抛出IllegalArgumentException异常。这个工具类是Spring框架util包(org.springframework.util)中的工具类

    参考:SpringBoot内置工具类之 断言 Assert

  • 相关阅读:
    提升性能的利器:深入解析SectionReader
    【HAL库】STM32CubeMX开发----STM32F407----ETH+LAN8720A+LWIP----ping通
    boost 压缩与解压缩流
    POJ1330最近公共祖先LCA
    RocketMQ 相关文档
    贯穿设计模式第一话--单一职责原则
    微服务框架 SpringCloud微服务架构 7 Feign 7.4 最佳实践分析
    vue中调用高德地图
    (附源码)spring boot大学毕业设计管理系统 毕业设计 030945
    c语言,c++,JAVA,Python应该怎么选择?
  • 原文地址:https://blog.csdn.net/vvv3171071/article/details/134097662