说明
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;
}
}
}