Java实例属性比较引发的一些思考
1、缘起
在编写一个判断数据是否变化的逻辑中,比如一个User类,需要比较两个User的实例属性是否全部相同,以此来判断属性值是否已经发生改变。
2、创建测试类
也是较为原始或无脑的写法,举个例子 创建比较的实体类
代码语言:javascript复制@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
private BigDecimal money;
}
编写测试类
代码语言:javascript复制public class PropertiesTest {
public static void main(String[] args) {
// 1、定义两个User实例
User user1 = new User(1, "zhangsan", new BigDecimal("25.7").setScale(2, RoundingMode.HALF_UP));
User user2 = new User(1, "zhangsan", new BigDecimal("25.70").setScale(2, RoundingMode.HALF_UP));
// 2、比较方法
}
}
方法一:普通的if-else判断
代码语言:javascript复制public static void main(String[] args) {
// 1、定义两个User实例
User user1 = new User(1, "zhangsan", new BigDecimal("25.7").setScale(2, RoundingMode.HALF_UP));
User user2 = new User(1, "zhangsan", new BigDecimal("25.70").setScale(2, RoundingMode.HALF_UP));
boolean flag = compareOne(user1, user2);
System.out.println(flag);
}
/**
* 方法一: 是否if
* @param user1 实例1
* @param user2 实例2
* @return 属性值是否相同
*/
public static boolean compareOne(User user1, User user2){
if (!Objects.equals(user1.getId(), user2.getId())) {
return false;
} else if (!Objects.equals(user1.getName(), user2.getName())) {
return false;
} else return Objects.equals(user1.getMoney(), user2.getMoney());
}
优点:实体类中需要比较字段较少时,代码逻辑简单。 缺点:实体类中需要比较的字段较多时,代码重复显得冗余。
方法二:通过反射遍历属性字段取得属性值
代码语言:javascript复制public static void main(String[] args) {
// 1、定义两个User实例
User user1 = new User(1, "zhangsan", new BigDecimal("25.7").setScale(2, RoundingMode.HALF_UP));
User user2 = new User(1, "zhangsan", new BigDecimal("25.70").setScale(2, RoundingMode.HALF_UP));
// boolean flag = compareOne(user1, user2);
boolean flag = compareTwo(user1, user2, new String[]{"id", "name", "money"});
System.out.println(flag);
}
/**
* 方法二: 使用反射
* @param user1 实例1
* @param user2 实例2
* @return 属性值是否相同
*/
public static boolean compareTwo(User user1, User user2, String[] fields){
boolean flag = true;
try {
for (String field : fields){
// 实例1
Field field1 = user1.getClass().getDeclaredField(field);
field1.setAccessible(true);
Object value1 = field1.get(user1);
// 实例2
Field field2 = user2.getClass().getDeclaredField(field);
field2.setAccessible(true);
Object value2 = field2.get(user2);
if ( !Objects.equals(value1, value2) ) {
flag = false;
break;
}
}
} catch (NoSuchFieldException | IllegalAccessException e) {
flag = false;
e.printStackTrace();
}
return flag;
}
优点:针对于实体类中需要比较字段较多的情况,可以针对封装工具方法。 缺点:实体类中需要比较的字段较多时,反射性能不是较优。
方法三:使用hutool工具
引入hutool工具包
代码语言:javascript复制<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.15</version>
</dependency>
代码语言:javascript复制public static void main(String[] args) {
// 1、定义两个User实例
User user1 = new User(1, "zhangsan", new BigDecimal("25.7").setScale(2, RoundingMode.HALF_UP));
User user2 = new User(1, "zhangsan", new BigDecimal("25.70").setScale(2, RoundingMode.HALF_UP));
// boolean flag = compareOne(user1, user2);
// boolean flag = compareTwo(user1, user2, new String[]{"id", "name", "money"});
boolean flag = compareThree(user1, user2);
System.out.println(flag);
}
/**
* 方法三: hutool工具类
* @param user1 实例1
* @param user2 实例2
* @return 属性值是否相同
*/
public static boolean compareThree(User user1, User user2){
Map<String, Object> map1 = BeanUtil.beanToMap(user1, true, true);
Map<String, Object> map2 = BeanUtil.beanToMap(user2, true, true);
if (map1.keySet().size() != map2.keySet().size()) {
return false;
}
for (Map.Entry<String, Object> str : map1.entrySet()){
if ( !Objects.equals(map2.get(str.getKey()), str.getValue())) {
return false;
}
}
return true;
}
优点:代码简洁,直接使用第三方工具包接口,比较逻辑简单 缺点:需要引入第三方jar包
总结
以上是对类实例字段值比较的一些思考,希望可以带来一些火花。