这段代码会抛出NPE,你造吗?----封装AssertUtil来友好地利用断言

发布时间 2023-05-26 16:29:49作者: buguge

运行下面代码,会抛出NPE。你知道为什么吗?

import cn.hutool.core.lang.Assert;

public class TestMain {

    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        Assert.isTrue(myClass.myProperty == 0);
    }


    private static class MyClass {
        private Integer myProperty;

    }
}

原因:初始化myClass对象后,Integer类型的myProperty属性的值是默认值null。此时,执行myClass.myProperty == 0,其实是调用了 Integer#intValue()方法进行拆箱操作,由于Integer对象是null,致使NPE。

上面代码在IDE里不会提示任何问题。而下面代码,IDE则会给出NPE提示。

 

 

我今天在写一个方法,利用断言判断数字类型属性取值的合法性时,恰好想到了这个问题点。就像上面的示例代码,还没到执行断言呢,就抛出了NPE了。显然,要先断言属性不为null。

如下是我改完后的程序代码

    public Result<UserSignDTO> userHasSign(UserSignQuery userSignQuery) {
        try {
            Assert.notNull(userSignQuery);
            Assert.notNull(userSignQuery.getIdcardNo());
            Assert.notNull(userSignQuery.getEnterpriseId());
            Assert.notNull(userSignQuery.getProviderId());
            Assert.isTrue(userSignQuery.getEnterpriseId()>0);
            Assert.isTrue(userSignQuery.getProviderId()>0);
            
            ...
            
        } catch (IllegalArgumentException e) {
            return Result.err(e.getMessage());
        }
    }

 

毋庸置疑,用断言可以增加代码的优雅度。而这一坨Assert,却跟优雅沾不上边。

 

于是乎,发挥点匠心精神吧。下面AssertUtil问世,基于Assert进行工具的封装。

package com.emax.common.util;

import cn.hutool.core.lang.Assert;

public class AssertUtil {
    /**
     * 断言所有对象是否不为{@code null} ,如果为{@code null} 抛出{@link IllegalArgumentException} 异常
     *
     * @param errMsg 断言失败的错误消息
     * @param objects
     */
    @SafeVarargs
    public static <T> void allNotNull(String errMsg, T... objects) throws IllegalArgumentException {
        for (T object : objects) {
            T t = errMsg == null ? Assert.notNull(object) : Assert.notNull(object, errMsg);
        }
    }

    /**
     * 断言所有对象是否不为{@code null} ,如果为{@code null} 抛出{@link IllegalArgumentException} 异常
     *
     * @param objects
     */
    public static <T> void allNotNull(T... objects) throws IllegalArgumentException {
        allNotNull(null, objects);
    }

    /**
     * 判断对象是数字,并且大于0
     *
     * @param number
     * @throws IllegalArgumentException
     */
    public static void gt0(Number number) throws IllegalArgumentException {
        Assert.notNull(number);
        Assert.isTrue(number.longValue() > 0);
    }
    
    ....其他断言方法
    
}

 

OK,改为使用AssertUtil断言,如下,是不是优雅?你品。

    public Result<UserSignDTO> userHasSign(UserSignQuery userSignQuery) {
        try {
            AssertUtil.allNotNull(userSignQuery, userSignQuery.getIdCardNo());
            AssertUtil.gt0(userSignQuery.getEnterpriseId());
            AssertUtil.gt0(userSignQuery.getProviderId());
            if (userSignQuery.getUserId() == 0 || StringUtils.isBlank(userSignQuery.getIdcardNo())) {
                throw new IllegalArgumentException("userId或身份证号码必传一项");
            }
            
            ...
            
        } catch (IllegalArgumentException e) {
            return Result.err(e.getMessage());
        }
    }