如何优雅实现忽略null与空字符串差异的对象比较?
如何优雅实现忽略null与空字符串差异的对象比较?
这个场景太戳人了!我之前做Swing桌面应用的时候也踩过一模一样的坑——GUI组件比如JTextField永远返回空字符串而非null,但数据库里对应的字段可能存的是null,直接用默认的equals比较总会搞出“假修改”的误判,手动写一堆null判断又显得特别啰嗦。
分享几个我用过的简洁优雅的方案,不用自己重复造轮子:
方案一:自定义轻量归一化工具方法(无依赖)
如果不想引入第三方库,最直接的方式是写一个小工具方法,把null统一转成空字符串,再进行比较。这样代码清晰,也不会增加额外依赖:
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertTrue; public class EqualityTest { @Test public void equalityTest() { User emptyNameUser = new User(""); User nullNameUser = new User(null); boolean usersEqual = equal(emptyNameUser, nullNameUser); assertTrue(usersEqual); } // 专门用于GUI场景的对象比较方法 private boolean equal(User userOne, User userTwo) { if (userOne == userTwo) return true; if (userOne == null || userTwo == null) return false; // 归一化处理:null转空字符串 return normalize(userOne.name).equals(normalize(userTwo.name)); // 如果有多个属性,依次添加判断即可: // && normalize(userOne.email).equals(normalize(userTwo.email)) // && ... } // 抽成通用工具方法,方便复用 private String normalize(String s) { return s == null ? "" : s; } static class User { String name; public User(String name) { this.name = name; } // 注意:不要修改实体默认的equals/hashCode! // 实体的equals通常用于业务主键判断,改动可能影响集合存储、JPA等逻辑 @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof User)) return false; User user = (User) o; return java.util.Objects.equals(name, user.name); } @Override public int hashCode() { return java.util.Objects.hashCode(name); } } }
方案二:借助第三方工具类(最简洁)
如果项目里已经引入了Apache Commons Lang或者Guava这类工具库,直接用现成的方法就能搞定,连归一化方法都不用自己写:
用Apache Commons Lang的StringUtils.defaultString
这个方法会自动把null转为空字符串,配合Objects.equals使用非常丝滑:
private boolean equal(User userOne, User userTwo) { if (userOne == userTwo) return true; if (userOne == null || userTwo == null) return false; return java.util.Objects.equals( org.apache.commons.lang3.StringUtils.defaultString(userOne.name), org.apache.commons.lang3.StringUtils.defaultString(userTwo.name) ); }
用Guava的Strings.nullToEmpty
和上面的效果完全一致,只是换了个库的方法:
private boolean equal(User userOne, User userTwo) { if (userOne == userTwo) return true; if (userOne == null || userTwo == null) return false; return java.util.Objects.equals( com.google.common.base.Strings.nullToEmpty(userOne.name), com.google.common.base.Strings.nullToEmpty(userTwo.name) ); }
方案三:自定义比较器(复用性强)
如果很多地方都需要这种忽略null/空字符串的比较,可以写一个专属的比较器类,统一处理逻辑,避免重复代码:
import org.apache.commons.lang3.StringUtils; public class UserGuiComparator { public boolean equals(User u1, User u2) { if (u1 == u2) return true; if (u1 == null || u2 == null) return false; // 所有需要比较的属性都统一处理 return StringUtils.defaultString(u1.name).equals(StringUtils.defaultString(u2.name)) && StringUtils.defaultString(u1.phone).equals(StringUtils.defaultString(u2.phone)) // 其他属性... ; } }
重要提醒
千万不要直接修改实体类的equals和hashCode方法!这些方法通常是基于业务主键或者全属性严格相等来实现的,改动后可能会导致集合存储、缓存、JPA实体判断等逻辑出现异常。专门写一个用于GUI数据校验的比较方法/比较器才是更安全的做法。
内容来源于stack exchange
相关产品推荐
相关产品推荐

