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

标签 java exception

在编写我自己的自定义 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 检查。

看一下 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() 的正确方法 fulfill its contract 。 现在请注意,在所有情况下,当对正确类型或 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 的 Effective Java 很好地描述了为什么它被认为是不好的做法。 ,第 57 条:仅在特殊情况下使用异常(exception):

Exceptions are, as their name implies, to be used only for exceptional conditions; they should never be used for ordinary control flow.

关于java.util.AbstractMap.equals() : what is it for try/catch?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23952508/

相关文章:

java - 当我尝试导入静态文件时出现 JSP 异常

python - 当我试图捕获多个异常时省略括号会发生什么?

c++ - 为什么 "non-standard syntax; use ' &' to create a pointer to member"在 CTOR 中使用线程?

Java 整数值超出指定范围的异常

java - 模型中的必填字段

java - java中如何删除数组中的索引

java - 我们可以在java中用它自己的异常来包装异常吗

java - 如何通过从文件中读取来反序列化 C++ 中的 ByteArray

java - 使用 GSON 将对象的 "list"(作为对象)解析为 JSON 中的整数对象( HashMap )

java - 重新排序分配并添加围栏