建議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 }
