繁体   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