Can Java help me avoid boilerplate code in equals()?

时光总嘲笑我的痴心妄想 提交于 2020-01-01 08:57:08

问题


I implement equals() the Java 7 way:

@Override
public boolean equals(Object obj)
{
    if (this == obj) return true;
    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    MyClass other = (MyClass) obj;
    return Objects.equal(myFirstField, other.myFirstField) &&
           Objects.equal(mySecondField, other.mySecondField);
}

Is there a way to reduce the code duplication?

I would prefer something like

@Override
public boolean equals(Object obj)
{
    if (Objects.equalsEarlyExit(this, obj)) return Objects.equalstEarlyExitResult(this, obj);
    MyClass other = (MyClass) obj;
    return Objects.equal(myFirstField, other.myFirstField) &&
           Objects.equal(mySecondField, other.mySecondField);
}

Or similar.


回答1:


Standard API Java with autoboxing and object creation inefficiencies:

import static java.util.Arrays.*;
import java.util.List;

class BrevityBeforeEfficiency {
  int foo;
  Object bar;
  boolean baz;

  @Override
  public boolean equals(Object obj) {
    return (obj instanceof BrevityBeforeEfficiency)
        && ((BrevityBeforeEfficiency) obj).values().equals(values());
  }

  @Override
  public int hashCode() {
    return values().hashCode();
  }

  private List<?> values() {
    return asList(foo, bar, baz);
  }
}



回答2:


You can use org.apache.commons.lang.builder.EqualsBuilder from commons-lang

Example:

public boolean equals(Object other) {
    return org.apache.commons.lang.builder.EqualsBuilder.reflectionEquals(this, other);
}

Other example:

private boolean equalsHelper(Object obj) {
    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    return true;
}


public boolean equals(Object obj) {

    if (this == obj) return true;

    if(!equalsHelper(ob)) {
      return false;
    }

    MyClass other = (MyClass) obj;
    return new EqualsBuilder()
      .append(myFirstField, other.myFirstField)
      .append(mySecondField, other.mySecondField).isEquals()
}



回答3:


mixing in a bit of inheritance:

public abstract class BusinessObject
{
    protected abstract Object[] getBusinessKeys();

    @Override
    public int hashCode()
    {
        return Objects.hash(getBusinessKeys());
    }

    @Override
    public boolean equals(Object obj)
    {
        if(obj == null) return false;

        if(obj == this) return true;

        if(obj.getClass() != getClass()) return false;

        BusinessObject other = (BusinessObject) obj;

        return Arrays.deepEquals(this.getBusinessKeys(), other.getBusinessKeys());
    }
}

so the only boilerplate code is to extend BusinessObject and the single-lined getBusinessKeys():

public class Node extends BusinessObject
{
    private final String code;
    private final String name;

    public Node(String code, String name)
    {
        this.code = code;
        this.name = name;
    }

    @Override
    protected Object[] getBusinessKeys()
    {
        return new Object[] { code, name };
    }
}

It's the simplest and cleanest that I can think :)




回答4:


Here could be an implementation:

public abstract class EqualsHelper<T> {

    @SuppressWarnings("unchecked")
    public static <U> boolean equals(U that, Object other, EqualsHelper<U> equalsHelper) {
        return that == other || other != null && that.getClass().equals(other.getClass()) && equalsHelper.equals(that, (U) other);
    }

    public abstract boolean equals(T that, T other);

}

Then:

@Override
public boolean equals(Object obj) {
    return EqualsHelper.equals(this, obj, new EqualsHelper<MyClass>() {

        @Override
        public boolean equals(MyClass that, MyClass other) {
            return Objects.equal(that.myFirstField, other.myFirstField)
                && Objects.equal(that.mySecondField, other.mySecondField);
        }

    });
}

I wonder if this can be considered as an anti-pattern, so don't hesitate to blame me if you think it actually is ;)



来源:https://stackoverflow.com/questions/25183872/can-java-help-me-avoid-boilerplate-code-in-equals

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!