建议46: equals应该考虑null值情景
继续上一建议的问题,我们解决了覆写equals的自反性问题,是不是就很完美了呢?再把main方法重构一下:
1 public class Client { 2 public static void main(String[] args) { 3 Person p1 = new Person("张三"); 4 Person p2 = new Person(null); 5 6 List<Person> l =new ArrayList<Person>(); 7 l.add(p1); 8 l.add(p2); 9 System.out.println("列表中是否包含张三:"+l.contains(p1)); 10 System.out.println("列表中是否包含张三 :"+l.contains(p2)); 11 } 12 } 13 14 class Person{ 15 private String name; 16 17 public Person(String _name){ 18 name = _name; 19 } 20 21 @Override 22 public boolean equals(Object obj) { 23 if(obj instanceof Person){ 24 Person p = (Person) obj; 25 return name.equalsIgnoreCase(p.getName().trim()); 26 } 27 return false; 28 } 29 30 public String getName() { 31 return name; 32 } 33 34 public void setName(String name) { 35 this.name = name; 36 } 37 }
很小的改动,那运行结果是什么呢?是两个true吗?我们来看运行结果:
列表中是否包含张三:true Exception in thread "main" java.lang.NullPointerException
竟然抛异常了!为什么p1就能在List中检查一遍,并且执行p1.equals方法,而到了p2就开始报错了呢?仔细分析一下程序,马上明白了:当执行到p2.equals(p1)时,由于p2的name是一个null值,所以调用name. equalsIgnoreCase方法时就会报空指针异常了!出现这种情形是因为覆写equals没有遵循对称性原则:对于任何引用x和y的情形,如果x.equals(y)返回true,那么y.equals(x)也应该返回true。
问题知道了,解决也很简单,增加name是否为空进行判断即可,修改后的equals代码如下:
1 public boolean equals(Object obj) { 2 if(obj instanceof Person){ 3 Person p = (Person) obj; 4 if(p.getName()==null || name==null){ 5 return false; 6 }else{ 7 return name.equalsIgnoreCase(p.getName()); 8 } 9 } 10 return false; 11 }