java.util.AbstractMap.equals():try/catch的作用是什么?
在编写自己的自定义MultiHashMap、multiTreeMap等类时(是的,我知道这些类在Guava Library中可用,但我需要提供一些不同的功能,因此我从头开始完全重写了这些类),我遇到了编写一个equals()方法的需要,该方法可以比较任何MultiMap,当且仅当两个多重映射的入口集相等(相同的键值映射,无论顺序如何)时返回true 当我在一个普通映射中保存多个值时,我将自己的方法与API方法java.util.AbstractMap.equals()进行了比较,结果发现它们非常相似,只是我没有使用任何try/catch(java 7):java.util.AbstractMap.equals():try/catch的作用是什么?,java,exception-handling,Java,Exception Handling,在编写自己的自定义MultiHashMap、multiTreeMap等类时(是的,我知道这些类在Guava Library中可用,但我需要提供一些不同的功能,因此我从头开始完全重写了这些类),我遇到了编写一个equals()方法的需要,该方法可以比较任何MultiMap,当且仅当两个多重映射的入口集相等(相同的键值映射,无论顺序如何)时返回true 当我在一个普通映射中保存多个值时,我将自己的方法与API方法java.util.AbstractMap.equals()进行了比较,结果发现它们非常
公共布尔等于(对象o){
如果(o==这个)
返回true;
如果(!(映射的实例))
返回false;
Map m=(Map)o;
如果(m.size()!=size())
返回false;
试一试{
迭代器i=entrySet().Iterator();
while(i.hasNext()){
条目e=i.next();
K key=e.getKey();
V value=e.getValue();
如果(值==null){
if(!(m.get(key)==null&&m.containsKey(key)))
返回false;
}否则{
如果(!value.equals(m.get(key)))
返回false;
}
}
}捕获(ClassCastException未使用){
返回false;
}捕获(NullPointerException未使用){
返回false;
}
返回true;
}
捕获到的异常是RuntimeException的异常,除此之外,我真的不知道它们在什么情况下会发生
有什么提示吗?我想,catch是用来捕获
V
类型中equals
方法的错误实现。调用value.equals(m.get(key))
可能会抛出ClassCastException
和或NullPointException
,而equals
是在V
中简单实现的
在实际的V
参数类型中,等于
的错误实现,可以很好地捕捉到:
class Whatever {
private int attr;
/* ... */
@Override public boolean equals(Object o) {
Whatever w= (Whatever)o; // possible ClassCastException
return (this.attr == w.attr); // possible NullPointerException
}
}
它们使用捕获异常来缩短
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()
的正确方法。
现在请注意,在所有情况下,当针对正确类型或null的测试失败时,equals()
方法返回false
。因此,您提供的代码中的想法是对所有检查进行ommit,并捕获异常。大概是这样的:
@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的第57项:仅在例外情况下使用例外,这一点被认为是不好的做法的原因已经非常清楚了:
例外情况,顾名思义,仅用于例外情况
条件不得将其用于普通控制流
答案似乎很简单:因为
Map.containsKey
方法可能会抛出这两个异常
从地图界面的文档中:
/**
* ....
* @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实现实际上并没有抛出这些异常,但一些自定义实现最终可能会抛出这些异常。处理这些异常最可靠的方法是在try-catch块中包装containsKey
另外:它被认为是坏习惯的一个原因是,你必须知道它是一个较短的形式。。。否则会导致问题,这一点可以证明;-)
/**
* ....
* @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);