递归判断对象或集合是否全为空的工具

说明

1、代码依赖了hutool的相关API,如果不想依赖hutool的话可以用阿帕奇或者spring的相关API进行替换。

2、对于是否为空的标准在代码里是写死的,详见注释。

代码实现

工具类的代码如下:

/**
 * {@link #isDeepEmpty(Object object, Boolean ignoreBoolean)}的重载方法,ignoreBoolean参数为false
 *
 * @param object 要判断的对象
 * @return object的所有属性是否都为空
 */
public static Boolean isDeepEmpty(Object object) {
    return isDeepEmpty(object, false);
}

/**
 * 递归判断对象及其所有父类的所有属性是否为空。<br>
 * 判断是否为空的标准:
 * <ul>
 * <li>如果字段类型为八大基本类型,则判断其值是否为默认值,详见{@link #isPrimitiveDefault(Object object, Boolean ignoreBoolean)}</li>
 * <li>如果字段类型为字符串,则调用{@link StrUtil#isEmpty(CharSequence str)}判断其是否为空字符串</li>
 * <li>如果字段类型为数组,则遍历递归判断每一个元素是否为空</li>
 * <li>如果字段类型为线性表,则遍历递归判断每一个元素是否为空</li>
 * <li>如果字段类型为Map,则调用{@link MapUtil#isEmpty}判断Map是否为空</li>
 * </ul>
 *
 * @param object        要判断的对象
 * @param ignoreBoolean 是否忽略布尔类型的比较,因为布尔类型只有真或者假,区分度较低
 * @return object的所有属性是否都为空
 */
public static Boolean isDeepEmpty(Object object, Boolean ignoreBoolean) {
    if (ObjectUtil.isBasicType(object)) {
        return isPrimitiveDefault(object, ignoreBoolean);
    } else if (object instanceof Iterable) {
        if (IterUtil.isNotEmpty((Iterable) object)) {
            Iterator iterator = ((Iterable) object).iterator();
            AtomicBoolean allEmpty= new AtomicBoolean(true);
            iterator.forEachRemaining(r->{
                if(!isDeepEmpty(r, ignoreBoolean)){
                    allEmpty.set(false);
                }
            });
            return allEmpty.get();
        }
        return true;
    } else if (object.getClass().isArray() && ArrayUtil.isNotEmpty(object)) {
        return Arrays.stream((Object[]) object).allMatch(e -> isDeepEmpty(e, ignoreBoolean));
    } else if (object instanceof CharSequence) {
        return StrUtil.isEmpty((CharSequence) object);
    } else if (object instanceof Map) {
        return MapUtil.isEmpty((Map) object);
    } else {
        Class<?> currentClass = object.getClass();
        while (currentClass != null && currentClass != Object.class) {
            Field[] declaredFields = currentClass.getDeclaredFields();
            for (int i = 0; i < declaredFields.length; i++) {
                Field field = declaredFields[i];
                if ((field.getName().contains("$") || "serialVersionUID".equals(field.getName()) || "class".equals(field.getName())))
                    continue;

                Object value = null;
                try {
                    value = field.get(object);
                } catch (IllegalAccessException e) {
                    field.setAccessible(true);
                    try {
                        value = field.get(object);
                    } catch (IllegalAccessException illegalAccessException) {
                        illegalAccessException.printStackTrace();
                    }
                }

                if (Objects.isNull(value))
                    continue;
                else {
                    return isDeepEmpty(value, ignoreBoolean);
                }
            }
            currentClass = currentClass.getSuperclass();
        }
    }
    return true;
}

/**
 * 判断传入的对象是否是基本类型的默认值。<br>
 * 当类成员为基本类型时,即使没有对其初始化,jvm会为其赋初始值,八大类型的默认值如下所示:<br>
 * <p>
 * boolean ---》 false<br>
 * <p>
 * char ---》 '/uoooo'(null)<br>
 * <p>
 * byte ---》 (byte)0<br>
 * <p>
 * short ---》 (short)0<br>
 * <p>
 * int ---》 0<br>
 * <p>
 * long ---》 0L<br>
 * <p>
 * float ---》 0.0f<br>
 * <p>
 * double ---》 0.0d<br>
 *
 * @param object        待判断的值
 * @param ignoreBoolean 是否忽略boolean类型的判断
 * @return 当object为基本类型的默认值时,返回{@code true},否则返回false
 */
public static boolean isPrimitiveDefault(Object object, Boolean ignoreBoolean) {
    String typeName = object.getClass().getSimpleName();
    if (typeName.equalsIgnoreCase(Integer.class.getSimpleName())) {
        return (int) object == 0;
    } else if (typeName.equalsIgnoreCase(Byte.class.getSimpleName())) {
        return (byte) object == 0;
    } else if (typeName.equalsIgnoreCase(Long.class.getSimpleName())) {
        return (long) object == 0L;
    } else if (typeName.equalsIgnoreCase(Double.class.getSimpleName())) {
        return (double) object == 0.0d;
    } else if (typeName.equalsIgnoreCase(Float.class.getSimpleName())) {
        return (float) object == 0.0f;
    } else if (typeName.equalsIgnoreCase(Character.class.getSimpleName())) {
        return (char) object == '\u0000';
    } else if (typeName.equalsIgnoreCase(Short.class.getSimpleName())) {
        return (short) object == 0;
    } else if (!ignoreBoolean && typeName.equalsIgnoreCase(Boolean.class.getSimpleName())) {
        return !(boolean) object;
    }
    return false;
}

测试案例

public class ObjectUtilTest {
    /**
     * 测试pojo
     */
    @Test
    public void testPojo() {
        Course course = new Course();
        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(course));
        course.setName("化学");
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(course));
    }

    /**
     * 测试基本数据类型的默认值
     */
    @Test
    public void testPrimitive() {
        int integer1 = 0;
        int integer2 = 1;
        byte byte1 = 0;
        byte byte2 = 1;
        long long1 = 0L;
        long long2 = 1L;
        double double1 = 0.0d;
        double double2 = 1.1d;
        float float1 = 0.0f;
        float float2 = 1.1f;
        char char1 = '\u0000';
        char char2 = '\u0006';
        short short1 = 0;
        short short2 = 1;
        boolean boolean1 = false;
        boolean boolean2 = true;

        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(integer1));
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(integer2));

        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(byte1));
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(byte2));

        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(long1));
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(long2));

        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(double1));
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(double2));

        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(float1));
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(float2));

        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(char1));
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(char2));

        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(short1));
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(short2));

        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(boolean1));
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(boolean2));
    }

    /**
     * 测试是否忽略boolean类型
     */
    @Test
    public void testIgnoreBoolean() {
        Boolean flag = false;
        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(flag));
        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(flag, false));


        Student student = new Student();
        student.setPretty(false);
        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(flag));

        student.setPretty(true);
        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(flag));

    }

    /**
     * 测试继承父类属性
     */
    @Test
    public void testExtend() {
        Student student = new Student();
        student.setName("李雷");
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(student));
    }

    /**
     * 测试pojo嵌套
     */
    @Test
    public void testNestPojo() {
        Student student = new Student();
        Course course = new Course();
        student.setCourse(course);
        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(student));
    }

    /**
     * 测试入参为数组
     */
    @Test
    public void testArray() {
        Student[] emptyStudentArray = {new Student(), new Student(), new Student()};
        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(emptyStudentArray));

        Student[] notEmptyStudentArray = {new Student("李华"), new Student(), new Student()};
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(notEmptyStudentArray));
    }

    /**
     * 测试迭代器
     */
    @Test
    public void testIterator() {
        List<Student> emptyList = new ArrayList<>();
        emptyList.add(new Student());
        emptyList.add(new Student());
        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(emptyList));

        List<Student> notEmptyList = new ArrayList<>();
        notEmptyList.add(new Student("小华"));
        notEmptyList.add(new Student());
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(notEmptyList));
    }

    /**
     * 测试入参字符串
     */
    @Test
    public void testString() {
        String empty = "";
        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(empty));

        String notEmpty = "aaa";
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(notEmpty));
    }

    /**
     * 测试入参为Map接口的实例
     */
    @Test
    public void testMap() {
        Map<Object, Object> map = new HashMap<>();
        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(map));
        map.put("name", "hutool");
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(map));
    }

    /**
     * 测试无效的属性名是否会被跳过 如:
     * <ul>
     * <li>以$开头的属性<li/>
     * <li>序列化属性serialVersionUID<li/>
     * <li>名字为class的属性<li/>
     * <ul/>
     */
    @Test
    public void testInvalidPropertyName() {
        SerialObject serialObject = new SerialObject();
        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(serialObject));
        serialObject.setName("hutool");
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(serialObject));
    }

    /**
     * 测试pojo嵌套集合的情况
     */
    @Test
    public void testPojoNextList() {
        Course course = new Course();
        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(course));
        List<Student> students = new ArrayList<>();
        course.setStudents(students);
        Assert.assertEquals(true, ObjectUtil.isDeepEmpty(course));
        Student student = new Student();
        student.setName("李明");
        students.add(student);
        Assert.assertEquals(false, ObjectUtil.isDeepEmpty(course));
    }

    /**
     * 课程类
     */
    class Course {
        private String name;
        private List<Student> students;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public void setStudents(List<Student> students) {
            this.students = students;
        }
    }

    class People {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }


    class SerialObject implements Serializable {
        private static final long serialVersionUID = 1L;

        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

    }

    class Student extends People {
        private String nickname;
        private Course course;
        private Boolean pretty;

        public Student() {
        }

        public Student(String nickname) {
            this.nickname = nickname;
        }

        public Course getCourse() {
            return course;
        }

        public void setCourse(Course course) {
            this.course = course;
        }

        public Boolean getPretty() {
            return pretty;
        }

        public void setPretty(Boolean pretty) {
            this.pretty = pretty;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值