前言
java中當對象需要判空的時候,大體都會直接 if(Object != null) ,而當我們的對象是 new Object()的時候,往往這種判斷不會起作用
因為此時對象已經被實例化,所以在項目中通常會用反射獲取Field從而判斷該屬性值是否為null,也就是常說的判斷對象中所有屬性不為null,本文講講我在項目中利用反射來判斷遇到的問題和一些坑
編寫工具類解決我們的問題
- 廢話不說,上代碼
/** * description:定義一個System.out.println的開(純屬個人習慣) **/ private static int objectNullSystemOutFlag = 0; /** * description:判斷當前對象是否為空(包括所有屬性為空) * * @author ZhangXihui * @param object 入參類 * @return boolean * @create 2019/6/3 17:34 **/ public static boolean objCheckIsNull(Object object) { if (object == null) { return true; } // 得到類對象 Class clazz = object.getClass(); // 得到所有屬性 Field[] fields = clazz.getDeclaredFields(); //定義返回結果,默認為true boolean flag = true; for (Field field : fields) { //設置權限(很重要,否則獲取不到private的屬性,不了解的同學補習一下反射知識) field.setAccessible(true); Object fieldValue = null; String fieldName = null; try { //得到屬性值 fieldValue = field.get(object); //得到屬性類型 Type fieldType = field.getGenericType(); //得到屬性名 fieldName = field.getName(); //打印輸出(調試用可忽略) if (objectNullSystemOutFlag == 1) { System.out.println("屬性類型:" + fieldType + ",屬性名:" + fieldName + ",屬性值:" + fieldValue); } } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } //只要有一個屬性值不為null 就返回false 表示對象不為null if (fieldValue != null) { flag = false; break; } } return flag; }
- 簡單的寫一個main,我們開始測試
-
public static void main(String[] args) { @ToString class User { private String username; private String password; public User() { } public User(String username, String password) { this.username = username; this.password = password; } } User user = new User(); System.out.println(user); //正常判斷 System.out.println(user == null); //使用反射的工具類 System.out.println( CommonFunction.objCheckIsNull(user)); }
- 輸出結果
-
User(username=null, password=null) false true
- 可見我們的工具類是好用的,但是在使用中會遇到一些問題,接下來說說我項目中遇到的問題和解決方法
問題與解決
- 場景一:在web開發中,實體類我們經常會進行序列化, implements Serializable 並為其添加一個 serialVersionUID
-
@ToString class User implements Serializable { private static final long serialVersionUID = 1996598449318251880L; private String username; private String password; public User() { } public User(String username, String password) { this.username = username; this.password = password; } }
-
產生問題:可以看到 serialVersionUID 是作為類中的一個屬性,而最開始構建的工具類沒有考慮到serialVersionUID 的存在
這樣會導致其返回結果一直為false,這也是一開始困擾我的原因,當我們專注於某一件事的時候,往往會忽略一些事情。解決:在判斷條件中忽略序列化字段名
//只要有一個屬性值不為null 就返回false 表示對象不為null 忽略序列化 if (fieldValue != null && !"serialVersionUID".equals(fieldName)) { flag = false; break; }
-
場景二:
業務需求場景:有一入參實體類,該實體類有30個屬性,其中有2個屬性會在程序中賦予默認值為10,這樣就導致該類有28個為null的屬性和2個為10的屬性,業務判斷為:除了默認值的兩個屬性之外如果所有屬性為null,那么我們就認為這個入參實體類什么也沒接到,也就認為它為"空"。
那么問題來了,難道我們要去挨個判斷剩余的28個字段為空么?很顯然不是的,根據上面我們從屬性判斷中剔除 serialVersionUID 的思路出發,我們會發現,業務中會經常出現,我們希望判斷某一實體類中,除了某些屬性或者某些值之外的屬性為null的情況,也就是我們判空的時候希望剔除掉某些屬性或者某些值,so,基於這些場景我改造了工具類,使其能夠實現我們的思路
-
/** * description:判斷當前對象是否為空(包括所有屬性為空) * 可選則在判斷規則中剔除某一字段,或者某一值 * * @author ZhangXihui * @param object 入參對象 * @param excludeNameList 要剔除的屬性名稱,沒有就傳空集合或者null * @param excludeValueList 要剔除的數值,沒有就傳空集合或者null * @return boolean * @create 2019/6/3 17:34 **/ public static boolean objCheckIsNull(Object object, List<String> excludeNameList, List<Object> excludeValueList) { if (object == null) { return true; } // 得到類對象 Class clazz = object.getClass(); // 得到所有屬性 Field[] fields = clazz.getDeclaredFields(); //判斷入參 boolean excludeNameListFlag = false; if (excludeNameList != null && excludeNameList.size() > 0) { excludeNameListFlag = true; } boolean excludeValueListFlag = false; if (excludeValueList != null && excludeValueList.size() > 0) { excludeValueListFlag = true; } //定義返回結果,默認為true boolean flag = true; for (Field field : fields) { field.setAccessible(true); Object fieldValue = null; String fieldName = null; try { //得到屬性值 fieldValue = field.get(object); //得到屬性類型 Type fieldType = field.getGenericType(); //得到屬性名 fieldName = field.getName(); //剔除指定屬性名的屬性值 if (excludeNameListFlag) { for (String s : excludeNameList) { if (fieldName.equals(s)) { fieldValue = null; break; } } } //剔除指定屬性值 if (excludeValueListFlag) { for (Object obj : excludeValueList) { if (obj.equals(fieldValue)) { fieldValue = null; break; } } } //打印輸出(調試用可忽略) if (objectNullSystemOutFlag == 1) { System.out.println("屬性類型:" + fieldType + ",屬性名:" + fieldName + ",屬性值:" + fieldValue); } } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } //只要有一個屬性值不為null 就返回false 表示對象不為null 忽略序列化 if (fieldValue != null && !"serialVersionUID".equals(fieldName)) { flag = false; break; } } //打印輸出(調試用可忽略) if (objectNullSystemOutFlag == 1) { System.out.println("忽略屬性: " + excludeNameList + " 忽略值: " + excludeValueList); } return flag; }
- 測試一下
-
public static void main(String[] args) { @ToString class User implements Serializable { private static final long serialVersionUID = 1996598449318251880L; private String username; private String password; private String sex; private String childSex; public User() { } public User(String sex, String childSex) { this.sex = sex; this.childSex = childSex; } } User user = new User("男性","男性"); System.out.println(user); //使用基礎的反射工具類 System.out.println( CommonFunction.objCheckIsNull(user)); //在判斷中剔除 value 為男性的屬性 System.out.println( CommonFunction.objCheckIsNull(user,null, Collections.singletonList("男性"))); //在判斷中剔除 屬性名 為 sex,childSex 的屬性 System.out.println( CommonFunction.objCheckIsNull(user,Arrays.asList("sex","childSex"),null)); }
- 結果
User(username=null, password=null, sex=男性, childSex=男性) false true true
- 成功
參考鏈接https://blog.csdn.net/qq_35566813/article/details/90914062 感謝