Question

When an object's value is equal i need to return it is true.

example

@Override
public int hashCode() {
return new HashCodeBuilder().append(value).toHashCode();
}

@Override
public boolean equals(final Object obj) {
if (obj instanceof NumberValTO) {
  final NumberValTO other = (NumberVal) obj;
  return new EqualsBuilder().append(value, other.getValue()).isEquals();
}
return false;
}

Is the above is fine or wrong?

I saw in few applications where hashcode is being multiple with each and every field of the table and not sure whether it is a correct approach.

Assume an entity has 4 columns Assume an entity has 2 columns

  1. Which is the best approach to generate the same?
  2. Also, do we need to implement hashcode() and equals() for a hibernate entity class?

Thanks.

Was it helpful?

Solution

Yes it's fine, assuming those are the Apache Commons helper classes you're using. @Vino is correct to point out that adding if (obj == this) return true; to the start of your equals method can be a worthwhile optimisation, but your methods look correct as is.

OTHER TIPS

Your example is fine as it provides a fair implementation of equals and hashcode methods. I am using this way in my project.

To answer you 1 question You can read through http://www.ideyatech.com/2011/04/effective-java-equals-and-hashcode/

To answer you 2 question follow link : Hibernate: When is it necessary to implement equals() and hashCode(), and if so, how?

Your equals and hashCode methods are both using the EqualsBuilder and HashCodeBuilder from Apache's commons-lang correctly, though you should add a reference check - if (obj == this) return true - to the equals method.

An argument I've recently been given against using EqualsBuilder and HashCodeBuilder was that it was less performant, so I tested it.

I created a HashMap, added 10K entries and then compared the look-up times for the same key object, once using a traditional equals and hashCode, then again with the EqualsBuilder and HashCodeBuilder. The idea is that getting the values by their key will hammer the both the equals and hashCode methods and give a good comparison of their performance.

While the EqualsBuilder and HashCodeBuilder implementations where slower, the difference was in the region of 60ns with an average look-up time of about 320ns for the commons-lang implementation and 260ns for the traditional approach (I've shown the code I used below).

IMHO this performance penalty should only be a concern where the equals and hashCode are called repeatedly over a large set of objects and even then, only where the small performance gain is worth sacrificing that clarity of you code.

Anyway, here's the class I used to test the performance difference:

public class Example
{
  private Type operationType;
  private long identity;
  private String name;
  private BigDecimal value;

  public Example(Type operationType, long identity, String name, BigDecimal value)
  {
    this.operationType = operationType;
    this.identity = identity;
    this.name = name;
    this.value = value;
  }

  public Example(Example example)
  {
    this.operationType = example.operationType;
    this.identity = example.identity;
    this.name = example.name;
    this.value = example.value;
  }

  public long getIdentity()
  {
    return identity;
  }

  public String getName()
  {
    return name;
  }

  public BigDecimal getValue()
  {
    return value;
  }

  @Override
  public boolean equals(Object obj)
  {
    if (Type.TRADITIONAL.equals(operationType))
    {
      if (this == obj)
      {
        return true;
      }
      if (obj == null || getClass() != obj.getClass())
      {
        return false;
      }

      Example example = (Example)obj;
      return getIdentity() == example.getIdentity()
        && ((getName() == null && example.getName() == null) || getName().equals(example.getName ()))
        && ((getValue() == null && example.getValue() == null) || getValue().equals(example.getValue()));
    }
    else
    {
      return this == obj || obj instanceof Example &&
        new EqualsBuilder()
          .append(getIdentity(), ((Example)obj).getIdentity())
          .append(getName(), ((Example)obj).getName())
          .append(getValue(), ((Example)obj).getValue())
          .isEquals();
    }
  }

  @Override
  public int hashCode()
  {
    if (Type.TRADITIONAL.equals(operationType))
    {
      int result = (int)(getIdentity() ^ (getIdentity() >>> 32));
      result = 31 * result + (getName() != null ? getName().hashCode() : 0);
      result = 31 * result + (getValue() != null ? getValue().hashCode() : 0);
      return result;
    }
    else
    {
      return new HashCodeBuilder().append(getIdentity()).append(getName()).append(getValue()).toHashCode();
    }
  }

  public static enum Type
  {
    TRADITIONAL,
    COMMONS
  }
}

And here's the test:

public class ExampleTest
{
  @Test
  public void testMapLookupWithTraditional() throws Exception
  {
    double total = 0;

    for (int i = 0; i < 10; i++)
    {
      total += testMapLookup(Example.Type.TRADITIONAL);
    }

    System.out.println("Overall Average: " + (total / 10));
  }

  @Test
  public void testMapLookupWithCommons() throws Exception
  {
    double total = 0;

    for (int i = 0; i < 10; i++)
    {
      total += testMapLookup(Example.Type.COMMONS);
    }

    System.out.println("Overall Average: " + (total / 10));
  }

  private double testMapLookup(Example.Type operationType) throws Exception
  {
    Map<Example, String> examples = new HashMap<Example, String>();

    while (examples.size() < 10000)
    {
      long now = System.currentTimeMillis();

      Example example = new Example(
        operationType,
        now,
        "EXAMPLE_" + now,
        new BigDecimal(now)
      );

      examples.put(example, example.getName());
      Thread.sleep(1);
    }

    int count = 0;
    double average = 0;
    double max = 0;
    double min = Double.MAX_VALUE;

    for (Example example : examples.keySet())
    {
      Example copiedExample = new Example(example);

      long start = System.nanoTime();

      examples.get(copiedExample);

      long duration = System.nanoTime() - start;

      average = ((average * count++) + duration) / count;

      if (max < duration) max = duration;
      if (min > duration) min = duration;
    }

    System.out.println("Average: " + average);
    System.out.println("Max: " + max);
    System.out.println("Min: " + min);

    return average;
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top