高质量编码--equals篇
高质量编码系列均是出自《编写高质量代码:改善Java程序的151个建议》一书。算是自己看完以后做的一个小结。
关于equals方法是我们经常使用的一个方法,相信很多朋友在面试复习的时候也常常碰到类似的知识点,如自定义的对象须要重写equals和hashcode方法...下面我也将提到这几点。
覆写equals方法不要识别不出自己
这一点我们在日常开发中可能会疏忽。
现在我们来看一个例子,我们手头有个person类,需要通过他们的名字来判断两者是否相等,因为Object类默认equals是通过地址来判断的。
我们重写了Person的equals方法,如下
@Override
public boolean equals(Object obj){
if(obj != null && obj.instanceof Person){
Person person = (Person)obj;
if(person.getName() != null && this.name != null){
return name.equalsIgnoreCase(p.getName.trim());
}
return false;
}
}
我们用重写后的类来看下面的例子
Person p1 = new Person("老张");
Person p2 = new Person("老李 ");
List<Person> list = new ArrayList();
list.add(p1);
list.add(p2);
System.out.println(list.contains(p1));
System.out.println(list.contains(p2));
大家猜猜看结果是什么呢?
true
false
相信有点兄嘚已经发现了,重写后的equals代码有一个问题,即存在list里的串未经过trim处理,而我们判断相等的时候却对传的person.getName()进行了trim处理,这显然是不合适的
改进方法也很简单,我们把trim的处理放到person.getName()逻辑中。
即
public String getName(){
return name == null ? name : name.trim();
}
当然,这样的话,equals方法中也就不需要进行trim处理了,直接比较两者的名字即可。
equals应考虑null值情景
其实我们上面的处理已经将传入值为null的情况考虑进去了
NPE是我们开发中很常见的一种异常,大家在开发中需要时刻提醒自己进行空值校验。说来惭愧,我在初入职场的时候犯了一个很低级的错误,稍微侃一下,工作中开发是分环境进行的,一些常用的属性我们一般都是放在配置文件中的,而要命的是,我在测试环境中进行了配置,却疏忽了配置正式环境,导致这个值上了正式取不到了,而且我在编码中并未对取出的值进行空值校验...结果我就不说了...
反正大家以我为反面教材,不要像我一样憨憨的,相信大家不会犯少发配置这种低级错误,但在编码中多进行空值判断,因为NPE导致的线上问题还是有不少的...
在equals中使用getClass进行类型判断,看需求
在equals类型判断的时候我们使用的是instanceof,但我们要注意这样一种情况,如我们这里提到的Person,其他类是可以继承Person,举几个例子,如Doctor医生,Teacher老师,Coder码农,是吧,码农也是人啊,然后我们进行了这样的比较doctor.equals(coder),返回的就有可能是true,当然,如果我们有这样的需求,一个人可能表面是个医生,其实还是个码农,对吧,这样的话用instanceof也没毛病,这里只是提一下,要注意有些场景用instanceof是不合理的
覆写equals方法必须覆写hashCode方法
这一块好多童鞋可能都了解过,JDK API也反复强调了这一点,但是为什么要这样呢,两者之间有啥联系?
我们先来看一个例子,Person类就是我们上面用到的那个
Map<Person,Object> map = new HashMap<Person,Object>(){
{
this.put(new Person("老张"),new Object());
}
};
System.out.println(map.containsKey(new Person("老张")));
输出结果大家可能没想到
false
蛤,为啥是false,整不明白了,不是根据名字判断相等么,原因就是因为HashMap
下面原文抄送
因为HashMap底层处理机制是以数组的方式保存Map条目(Map Entry)的,这其中的关键是这个数组下标的处理机制:根据传入元素hashCode方法的返回值决定其数组的下标,如果该数组位置没有条目,则插入,加入到Map条目的链表中。同理,检查键是否存在也是根据哈希码确定位置,然后遍历查找键值的
说白了就是我先根据hashCode判断,再拿equals方法进行的判断,如果hashCode判断你不在,sorry,拜拜了,直接不看equals
那就说明,这hashCode有问题啊,我这明明要相等啊,所以我们得重写这个方法
其实也很简单,如下
@Override
public int hashCode() {
return new HashCodeBuilder().append(name).toHashCode();
}
HashCodeBuilder这个类是org.apache.commons.lang.builder包下的一个哈希码生成工具,使用方便,大家直接集成就可以用了,为啥不自己写,老大说了,哈希码生成有多种算法,自己写麻烦,事多,有工具干嘛不用[旺柴][旺柴]
mvnrepository
给大家提供一个网址,大家需要依赖可以上面查一下https://mvnrepository.com/