簡體   English   中英

java.util.AbstractMap.equals():try / catch是什么?

[英]java.util.AbstractMap.equals() : what is it for try/catch?

在編寫自己的自定義MultiHashMap,multiTreeMap等類時(是的,我知道Guava庫中提供了這些類,但是我需要提供一些不同的功能,所以我從頭開始完全重寫了這些功能)遇到了編寫equals( )可以比較任何MultiMap的方法,當且僅當兩個MultiMap的entrySet相等時才返回true(相同的鍵值映射,而不考慮順序)。

當我將一個多值保存在一個普通Map中時,我將自己的方法與API方法java.util.AbstractMap.equals()進行了比較,結果發現它們非常相似,除了我不使用任何try / catch( Java 7):

public boolean equals(Object o) {
    if (o == this)
        return true;

    if (!(o instanceof Map))
        return false;
    Map<K,V> m = (Map<K,V>) o;
    if (m.size() != size())
        return false;

    try {
        Iterator<Entry<K,V>> i = entrySet().iterator();
        while (i.hasNext()) {
            Entry<K,V> e = i.next();
            K key = e.getKey();
            V value = e.getValue();
            if (value == null) {
                if (!(m.get(key)==null && m.containsKey(key)))
                    return false;
            } else {
                if (!value.equals(m.get(key)))
                    return false;
            }
        }
    } catch (ClassCastException unused) {
        return false;
    } catch (NullPointerException unused) {
        return false;
    }

    return true;
}

捕獲的異常是RuntimeException的異常,除此之外,我無法真正弄清它們可能在哪種情況下發生。

有什么提示嗎?

他們使用捕獲異常使equals()代碼更短。 我認為這不是一個很好的做法,但是可以。 它們通過捕獲異常來替換許多if -check。

看一下Eclipse自動生成的equals()方法的示例:

public class Person {
    final private String firstName;
    final private String lastName;
    ...
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        Person other = (Person) obj;
        if (firstName == null) {
            if (other.firstName != null) {
                return false;
            }
        }
        else if (!firstName.equals(other.firstName)) {
            return false;
        }
        if (lastName == null) {
            if (other.lastName != null) {
                return false;
            }
        }
        else if (!lastName.equals(other.lastName)) {
            return false;
        }
        return true;
    }
}

這是實現equals()以完全履行合同的正確方法。 現在請注意,在所有情況下,如果針對正確類型或null的某些測試失敗,則equals()方法將返回false 因此,您提供的代碼中的想法是省略所有檢查並僅捕獲異常。 像這樣:

@Override
public boolean equals(Object obj) {
    try {
        // Ommit any type-checks before type-casting
        // and replace them with catching ClassCastException:
        final Person other = (Person) obj;
        // Ommit any null-checks before using the references
        // and replace them with catching NullPointerException:
        if (firstName.equals(other.firstName)
                && lastName.equals(other.lastName)) {
            return true;
        }
    }
    catch (ClassCastException | NullPointerException unused) {
        // swallow the exception as it is not an error here
    }
    return false;
}

如您所見,該代碼執行相同的操作,但是明顯更短。 但是,通常認為這是不好的做法。 我仍然必須承認代碼可讀性更好:)

約書亞·布洛赫(Joshua Bloch)的《 有效的Java》Effective Java )項目57:僅在特殊情況下使用例外:

顧名思義,異常僅用於特殊情況; 它們絕對不能用於普通的控制流程。

我認為,catch旨在捕獲V類型中equals方法的錯誤實現。 當在V天真地實現equals時,調用value.equals(m.get(key))可能引發ClassCastExceptionNullPointException

在實際的V參數類型中對equals的錯誤實現很容易被發現:

class Whatever {
  private int attr;
  /* ... */
  @Override public boolean equals(Object o) {
    Whatever w= (Whatever)o; // possible ClassCastException
    return (this.attr == w.attr); // possible NullPointerException
  }
}

答案似乎很簡單:因為Map.containsKey方法可能會拋出這兩個異常。

從Map界面的文檔中:

/**
 * ....
 * @throws ClassCastException if the key is of an inappropriate type for
 *         this map (optional)
 * @throws NullPointerException if the specified key is null and this map
 *         does not permit null keys (optional)
 */
boolean containsKey(Object key);

盡管AbstractMap中的containsKey實現實際上並沒有引發這些異常,但是某些自定義實現最終可能會這樣做。 處理這些異常的最可靠方法是將containsKey包裝在try-catch塊中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM