高质量编码--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/

posted on 2020-03-29 16:20  布衣少年  阅读(165)  评论(0编辑  收藏  举报

导航