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.
Is the below is correct equals and hashCode implementation in Java?
Frage
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
- Which is the best approach to generate the same?
- Also, do we need to implement hashcode() and equals() for a hibernate entity class?
Thanks.
Lösung
Andere Tipps
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;
}
}