java判斷物件是否為空

自在现实發表於2024-06-25

最近專案中遇到一個問題,在使用者沒填資料的時候,我們需要接收從前端傳過來的物件為null,但是前端說他們一個一個判斷特別麻煩,只能傳個空物件過來,我第一個想法就是可以透過反射來判斷物件是否為空。

第一版:

User.java

public class User {
private String username;

private Boolean active;

private Long id;
// 省略get和set方法

}
ReflectUtil.java

public class ReflectUtil {
public static boolean isObjectNull(Object obj){
if (obj != null) {
Class<?> objClass = obj.getClass();
Method[] declaredMethods = objClass.getDeclaredMethods();
if (declaredMethods.length > 0) {
int methodCount = 0; // get 方法數量
int nullValueCount = 0; // 結果為空

            for (Method declaredMethod : declaredMethods) {
                String name = declaredMethod.getName();
                if (name.startsWith("get") || name.startsWith("is")){
                    methodCount += 1;
                    try {
                        Object invoke = declaredMethod.invoke(obj);
                        if (invoke == null) {
                            nullValueCount += 1;
                        }
                    } catch (IllegalAccessException | InvocationTargetException e){
                        e.printStackTrace();
                    }
                }
            }
            return methodCount == nullValueCount;
        }
    }
    return false;
}

}

TestReflect.java

public class TestReflect {
public static void main(String[] args) {
User user = new User();
System.out.println(ReflectUtil.isObjectNull(user));
}
}
結果:

true
第一版 獲取一個類的宣告的方法,判斷方法如果以get或者is開頭就是get方法,然後透過反射呼叫改方法獲取結果,再判斷結果是否為空,如果結果為null的話就把nullValueCount+1,最後返回結果為空的值的數量和get方法數量比較的結果,如果兩者數量相同則說明該物件為空,反之不為空。
第一版也可以判斷一個物件是否為空,但前提是物件必須使用包裝類,沒有預設值的就不行了,當然你也可以根據型別和返回值結果來判斷物件是否為空,但是如果想忽略某個屬性不做判斷,改起來就有點麻煩了。 後來想知道spring 的BeanUtils 是怎麼實現屬性複製的就看了一下,發現了新的方法,於是就有了第二版。

第二版:

/**
* 判斷物件是否為空,
* @param obj
* @param ignoreProperties 忽略的屬性
* @return 如果get 方法的數量等於 屬性為空的數量 返回true,否則false
*/
public static boolean isNullObject(Object obj , String... ignoreProperties) throws IntrospectionException {
if (obj != null) {
Class<?> objClass = obj.getClass();
BeanInfo beanInfo = Introspector.getBeanInfo(objClass);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

        List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);

        int count = 1; // 結果為空的屬性數量 初始化為1 去除Object的getClass方法
        int propertyCount = propertyDescriptors.length; // 屬性數量
        if (ignoreList != null){
            propertyCount -= ignoreList.size();
        }

        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            Method readMethod = propertyDescriptor.getReadMethod();
            String name = propertyDescriptor.getName();
            if (readMethod != null && (ignoreList == null || !ignoreList.contains(name))) {
                Class<?> returnType = readMethod.getReturnType();
                String typeName = returnType.getSimpleName();
                Object invoke = null;
                try {
                    invoke = readMethod.invoke(obj);
                    if (invoke == null) {
                        count+=1;
                    }else {
                        switch (typeName) {
                            case "String":
                                if ("".equals(invoke.toString().trim())) {
                                    count += 1;
                                }
                                break;
                            case "Integer":
                                if ((Integer) invoke <= 0) {
                                    count += 1;
                                }
                                break;
                            case "int":
                                if ((int) invoke <= 0) {
                                    count += 1;
                                }
                                break;
                            case "double":
                                if ((double) invoke <= 0.0d) {
                                    count += 1;
                                }
                                break;
                            case "Double":
                                if ((Double) invoke <= 0.0D) {
                                    count += 1;
                                }
                                break;
                            case "float":
                                if ((float) invoke <= 0.0f) {
                                    count += 1;
                                }
                                break;
                            case "Float":
                                if ((Float) invoke <= 0.0F) {
                                    count += 1;
                                }
                                break;
                            case "Long":
                                if ((Long) invoke <= 0L) {
                                    count += 1;
                                }
                                break;
                            case "long":
                                if ((long) invoke <= 0L) {
                                    count += 1;
                                }
                                break;
                        }
                    }
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        return propertyCount == count;
    }
    return true;
}

第一版和第二版思想基本都是一樣的,都是透過讀方法去判斷返回值是否為空,只不過第二版在第一版上加強了可以忽略屬性這個功能。
透過spring 的beanutils發現PropertyDescriptor這個類,從名字看來是個屬性描述器,描述屬性相關的東西,透過屬性描述器可以獲取bean的屬性名稱,讀寫方法,使用起來還挺方便。
透過Introspector內省類的靜態方法getBeanInfo(Class<?> beanClass)獲取BeanInfo,然後透過BeanInfo物件的getPropertyDescriptors()就可以返回屬性描述器。
由於沒有太多研究就不多介紹了。
如果你還有其他方法判斷一個物件是否為空請留言,謝謝

能力有限,水平一般,如有錯誤,請多指出。

相關文章