如何在不增加圈复杂度的情况下覆盖等于?
How to override equals without increasing cyclomatic complexity?
我最近在我最近的 Java 项目的域对象中重写了一些 equals
方法。当我们使用 Sonar 计算我们的代码指标时,我立即看到这些 类 的圈复杂度增加到阈值以上。
我想知道是否有聪明的方法、模式或选项来保持这个指标较低,尽管有一些更复杂的 equals
方法。
编辑:这是我的例子之一,没有什么特别具体的,只是为了让我们知道我们在说什么。
@Override
public boolean equals(Object o) {
if (o instanceof MyKey) {
MyKey other = (MyKey) o;
if (this.foo.longValue() == other.getFoo().longValue() &&
this.bar.equalsIgnoreCase(other.getBar()) &&
this.foobar.shortValue() == other.getFoobar().longValue()){
return true;
}
}
return false;
}
@Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + foo.hashCode();
hash = 53 * hash + bar.hashCode();
hash = 53 * hash + foobar.hashCode();
return hash;
}
您可以使用 Apache 的 EqualsBuilder:
public boolean equals(Object obj) {
if (obj == null) { return false; }
if (obj == this) { return true; }
if (obj.getClass() != getClass()) {
return false;
}
MyClass rhs = (MyClass) obj;
return new EqualsBuilder()
.appendSuper(super.equals(obj))
.append(field1, rhs.field1)
.append(field2, rhs.field2)
.append(field3, rhs.field3)
.isEquals();
}
你没有,但你应该经常检查 null
s。 foo
可能是 null
,结果是 NullPointerException
.
this.foo.longValue() == other.foo.longValue()
幸运的是 Objects
实用程序 class 会自动检查 null
s,从而避免了很多问题。
@Override
public boolean equals(Object object) {
if (object == null)
return false;
if (!(object instanceof MyObject))
return false;
MyObject other = (MyObject) object;
//@formatter:off
return Objects.equals(getX(), other.getX()) &&
Objects.equals(getY(), other.getY()) &&
Objects.equals(getZ(), other.getZ()));
//@formatter:on
}
@Override
public int hashCode() {
return Objects.hashCode(getX(), getY(), getZ());
}
如果要检查的字段很多,您可以选择将其添加到 equals
方法的开头。
if (object == this)
return true;
理论上它可以在某些边缘情况下节省一些计算量。
在我看来,唯一真正有用的是良好的缩进。我总是将这些线包裹在一对 //@formatter:off
和 //@formatter:on
之间。无论如何,这是样板代码:非常容易编写,非常容易出错。
但是,在您的情况下,您正在使用 equalsIgnoreCase
检查相等性。可惜Objects
没有这样的方法。您可以很容易地构建自己的。
public final class Strings {
public static boolean equalsIgnoreCase(String a, String b) {
return a == null ? b == null : a.equalsIgnoreCase(b);
}
private Strings() {
}
}
然后像这样使用它
return Objects.equals (getX(), other.getX()) &&
Strings.equalsIgnoreCase (getY(), other.getY()) &&
Objects.equals (getZ(), other.getZ()));
我最近在我最近的 Java 项目的域对象中重写了一些 equals
方法。当我们使用 Sonar 计算我们的代码指标时,我立即看到这些 类 的圈复杂度增加到阈值以上。
我想知道是否有聪明的方法、模式或选项来保持这个指标较低,尽管有一些更复杂的 equals
方法。
编辑:这是我的例子之一,没有什么特别具体的,只是为了让我们知道我们在说什么。
@Override
public boolean equals(Object o) {
if (o instanceof MyKey) {
MyKey other = (MyKey) o;
if (this.foo.longValue() == other.getFoo().longValue() &&
this.bar.equalsIgnoreCase(other.getBar()) &&
this.foobar.shortValue() == other.getFoobar().longValue()){
return true;
}
}
return false;
}
@Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + foo.hashCode();
hash = 53 * hash + bar.hashCode();
hash = 53 * hash + foobar.hashCode();
return hash;
}
您可以使用 Apache 的 EqualsBuilder:
public boolean equals(Object obj) {
if (obj == null) { return false; }
if (obj == this) { return true; }
if (obj.getClass() != getClass()) {
return false;
}
MyClass rhs = (MyClass) obj;
return new EqualsBuilder()
.appendSuper(super.equals(obj))
.append(field1, rhs.field1)
.append(field2, rhs.field2)
.append(field3, rhs.field3)
.isEquals();
}
你没有,但你应该经常检查 null
s。 foo
可能是 null
,结果是 NullPointerException
.
this.foo.longValue() == other.foo.longValue()
幸运的是 Objects
实用程序 class 会自动检查 null
s,从而避免了很多问题。
@Override
public boolean equals(Object object) {
if (object == null)
return false;
if (!(object instanceof MyObject))
return false;
MyObject other = (MyObject) object;
//@formatter:off
return Objects.equals(getX(), other.getX()) &&
Objects.equals(getY(), other.getY()) &&
Objects.equals(getZ(), other.getZ()));
//@formatter:on
}
@Override
public int hashCode() {
return Objects.hashCode(getX(), getY(), getZ());
}
如果要检查的字段很多,您可以选择将其添加到 equals
方法的开头。
if (object == this)
return true;
理论上它可以在某些边缘情况下节省一些计算量。
在我看来,唯一真正有用的是良好的缩进。我总是将这些线包裹在一对 //@formatter:off
和 //@formatter:on
之间。无论如何,这是样板代码:非常容易编写,非常容易出错。
但是,在您的情况下,您正在使用 equalsIgnoreCase
检查相等性。可惜Objects
没有这样的方法。您可以很容易地构建自己的。
public final class Strings {
public static boolean equalsIgnoreCase(String a, String b) {
return a == null ? b == null : a.equalsIgnoreCase(b);
}
private Strings() {
}
}
然后像这样使用它
return Objects.equals (getX(), other.getX()) &&
Strings.equalsIgnoreCase (getY(), other.getY()) &&
Objects.equals (getZ(), other.getZ()));