天天看點

擷取對象屬性值改動的屬性集合的正确姿勢(拒絕大量If-else代碼)

弊端:

如果需要增減屬性,需要增減If-else代碼,會有代碼量大,不容易維護等問題。

解決方案:

那麼我們可以将屬性和值的映射成鍵值對,比較屬性的值是否相同來判斷值是否改動過。

由于未必是所有屬性比對,是以可以建立一個注解,允許隻比對帶有此注解的屬性。

如果兩個對象類型不同,隻比較其中兩個屬性,且屬性名不同怎麼辦?

那麼可以在注解上加上别名,這樣比對别名就好了。

上代碼(建議從github拉取):

github位址:

https://github.com/chujianyun/filed2value

pom檔案配置:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0

http://maven.apache.org/xsd/maven-4.0.0.xsd">

   <modelVersion>4.0.0</modelVersion>

   <groupId>com.chujianyun</groupId>

   <artifactId>field2hash</artifactId>

   <version>1.0-SNAPSHOT</version>

   <dependencies>

       <dependency>

           <groupId>org.projectlombok</groupId>

           <artifactId>lombok</artifactId>

           <version>1.18.6</version>

       </dependency>

           <groupId>junit</groupId>

           <artifactId>junit</artifactId>

           <version>4.11</version>

       <!--

https://mvnrepository.com/artifact/org.apache.commons/commons-lang3

-->

           <groupId>org.apache.commons</groupId>

           <artifactId>commons-lang3</artifactId>

           <version>3.8.1</version>

   </dependencies>

   <build>

       <plugins>

           <plugin>

               <groupId>org.apache.maven.plugins</groupId>

               <artifactId>maven-compiler-plugin</artifactId>

               <configuration>

                   <source>1.8</source>

                   <target>1.8</target>

               </configuration>

           </plugin>

       </plugins>

   </build>

</project>

注解類:

package com.chujianyun.field2hash.annotation;

import java.lang.annotation.*;

/**

* 待校驗的屬性

* 允許指定别名

*

* @author [email protected]

* @date 2019年03月16日

*/

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface Field2Value {

   String alias() default "";

}

package com.chujianyun.field2value.annotation;

* 需要忽略的屬性

* @date: 2019-04-08 10:15

public @interface Ignore {

工具類

package com.chujianyun.field2value.utils;

import com.chujianyun.field2value.annotation.Field2Value;

import com.chujianyun.field2value.annotation.Ignore;

import java.lang.reflect.Field;

import java.util.HashMap;

import java.util.HashSet;

import java.util.Map;

import java.util.Set;

* 對象屬性名到其值的映射工具

* <p>

* 可用來比較值發生了變化的屬性

public class Field2ValueUtil {

   /**

    * 根據對象和屬性名+别名的集合擷取屬性集合

    *

    * @param object            待解析的對象

    * @param fieldOrAliasNames 屬性名或者别名的集合

    * @return 屬性集合

    */

   public static Set<Field> getFieldsByFieldOrAliasNames(Object object, Set<String> fieldOrAliasNames) {

       if (object == null || fieldOrAliasNames == null || fieldOrAliasNames.isEmpty()) {

           return new HashSet<>(0);

       }

       Set<Field> fields2get = new HashSet<>(fieldOrAliasNames.size());

       Class<?> clazz = object.getClass();

       Field[] declaredFields = clazz.getDeclaredFields();

       for (Field field : declaredFields) {

           // 帶注解

           if (field.isAnnotationPresent(Field2Value.class)) {

               Field2Value annotation = field.getAnnotation(Field2Value.class);

               String alias = annotation.alias();

               if (fieldOrAliasNames.contains(alias) || fieldOrAliasNames.contains(field.getName())) {

                   fields2get.add(field);

                   break;

               }

           } else {

               if (fieldOrAliasNames.contains(field.getName())) {

           }

       return fields2get;

   }

    * 根據屬性的名稱或者别名的名稱擷取屬性的值

    * @param object           對象

    * @param fieldNameOrAlias 屬性名或别名

    * @return 該屬性的值

   public static Object getValueByFieldNameOrAlias(Object object, String fieldNameOrAlias) throws IllegalAccessException {

       Field field2resolve = null;

           // 直接屬性名相同

           if (field.getName().equals(fieldNameOrAlias)) {

               field2resolve = field;

               break;

           // 别名相同

               if (!"".equals(alias) && alias.equals(fieldNameOrAlias)) {

                   field2resolve = field;

       if (field2resolve != null) {

           field2resolve.setAccessible(true);

           return field2resolve.get(object);

       return null;

    * 擷取兩個對象屬性的值不同的所有屬性名稱

    * @param object1                 第一個對象

    * @param object2                 第二個對象

    * @param onlyCompareCommonFields 設計費

    * @return 屬性的值不同的所有屬性名稱

   public static Set<String> getDifferentValueFieldOrAliasNames(Object object1, Object object2, boolean resolveAllField, boolean onlyCompareCommonFields) throws IllegalAccessException {

       Map<String, Object> field2ValuePair1 = getField2ValuePair(object1, resolveAllField);

       Set<String> keySet1 = field2ValuePair1.keySet();

       Map<String, Object> field2ValuePair2 = getField2ValuePair(object2, resolveAllField);

       Set<String> keySet2 = field2ValuePair2.keySet();

       if (keySet1.isEmpty()) {

           return keySet2;

       if (keySet2.isEmpty()) {

           return keySet1;

       Set<String> fieldsWithDifferentValue = new HashSet<>();

       // 隻比較公共屬性

       for (Map.Entry<String, Object> entry : field2ValuePair1.entrySet()) {

           String fieldName = entry.getKey();

           Object value1 = entry.getValue();

           Object value2 = field2ValuePair2.get(fieldName);

           boolean sameHashCode = (value1.hashCode() == value2.hashCode());

           boolean sameObject = value1.equals(value2);

           if (!(sameHashCode && sameObject)) {

               fieldsWithDifferentValue.add(fieldName);

       // 不相同的fields

       if (!onlyCompareCommonFields) {

           Set<String> keySet1Copy = new HashSet<>(keySet1);

           Set<String> keySet2Copy = new HashSet<>(keySet2);

           keySet1.removeAll(keySet2);

           keySet2Copy.removeAll(keySet1Copy);

           fieldsWithDifferentValue.addAll(keySet1);

           fieldsWithDifferentValue.addAll(keySet2Copy);

       return fieldsWithDifferentValue;

    * 擷取屬性及其對應值得hash值(可能有hash沖突,謹慎使用)

    * @param resolveAllField 解析所有屬性

    * @return 屬性--> 值hash

   public static <T> Map<String, Integer> getField2HashPair(T object, boolean resolveAllField) throws IllegalAccessException {

       if (object == null) {

           return new HashMap<>(0);

       Map<String, Object> field2ValuePair = getField2ValuePair(object, resolveAllField);

       Map<String, Integer> field2hashPairMap = new HashMap<>(field2ValuePair.size());

       field2ValuePair.forEach((key, value) -> field2hashPairMap.put(key, value.hashCode()));

       return field2hashPairMap;

    * 擷取屬性及其對應值的映射(推薦使用)

    * @return 屬性--> 值

   public static <T> Map<String, Object> getField2ValuePair(T object, boolean resolveAllField) throws IllegalAccessException {

       Map<String, Object> field2hashMap = new HashMap<>(declaredFields.length);

           field.setAccessible(true);

           String key = field.getName();

           // 忽略的屬性

           if (field.isAnnotationPresent(Ignore.class)) {

               continue;

           // 解析所有

           if (resolveAllField) {

               field2hashMap.put(key, field.get(object));

           // 隻解析帶@Field2Value注解的

               if (!"".equals(alias)) {

                   key = alias;

       return field2hashMap;

實體類

package com.chujianyun.field2value;

import lombok.Data;

* Cat測試實體

@Data

public class Cat implements Cloneable {

   private String name;

   private Byte age;

   @Field2Value(alias = "nick")

   private String nickName;

   @Field2Value

   private String ownerName;

   @Ignore

   private String role;

   @Override

   public Object clone() throws CloneNotSupportedException {

       return super.clone();

測試類:

package com.chujianyun.field2hash.utils;

import com.chujianyun.field2hash.Cat;

import org.apache.commons.lang3.ObjectUtils;

import org.junit.Before;

import org.junit.Test;

import static org.junit.Assert.*;

* Field2ValueUtil測試類

public class Field2ValueUtilTest {

   private Cat cat = null;

   private String age = "age";

   @Before

   public void init() {

       // 原始屬性

       cat = new Cat();

       cat.setAge(Byte.parseByte("1"));

       cat.setName("喵咪");

       cat.setNickName("tomcat");

       cat.setOwnerName("了凡");

   @Test

   public void filed2hashTest() throws IllegalAccessException {

       Map<String, Integer> field2HashPair = Field2ValueUtil.getField2HashPair(cat, false);

       System.out.println("修改前" + field2HashPair);

       cat.setOwnerName("張無忌");

       Map<String, Integer> field2HashPair2 = Field2ValueUtil.getField2HashPair(cat, false);

       System.out.println("修改後" + field2HashPair2);

    * 擷取屬性值不同的屬性名

   public void getDifferentValueFieldNames() throws IllegalAccessException {

       Cat catClone = ObjectUtils.clone(cat);

       catClone.setOwnerName("張無忌");

       // 兩個對象不同的屬性名活别名集合

       Set<String> differentValueFieldOrAliaNames = Field2ValueUtil.getDifferentValueFieldOrAliasNames(cat, catClone, false, true);

       System.out.println(differentValueFieldOrAliaNames);

       assertEquals(differentValueFieldOrAliaNames.size(), 1);

       // 屬性名或别名集合

       for (String fieldNameOrAlias : differentValueFieldOrAliaNames) {

           System.out.println(Field2ValueUtil.getValueByFieldNameOrAlias(catClone, fieldNameOrAlias));

       // 屬性集合

       Set<Field> fieldsByFieldOrAliasNames = Field2ValueUtil.getFieldsByFieldOrAliasNames(catClone, differentValueFieldOrAliaNames);

        System.out.println(fieldsByFieldOrAliasNames);

    * 解析待注解的屬性

   public void getField2HashPair() throws IllegalAccessException {

       Map<String, Integer> field2HashPair1 = Field2ValueUtil.getField2HashPair(cat, false);

       System.out.println(field2HashPair1);

       assertNull(field2HashPair1.get(age));

    * 解析所有屬性

   public void getField2HashPairAllFields() throws IllegalAccessException {

       Map<String, Integer> field2HashPair = Field2ValueUtil.getField2HashPair(cat, true);

       System.out.println(field2HashPair);

       assertNotEquals(field2HashPair.get(age), "1");

————————————————

版權聲明:本文為CSDN部落客「明明如月學長」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。

原文連結:

https://blog.csdn.net/w605283073/article/details/88606762