2019.04.20 Implementing .equals() and .hashCode() in Java Easier method. - GlenKPeterson/One-off_Examples GitHub Wiki
Implementing .equals() and .hashCode() for database classes can be as simple as this:
@Override
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
public boolean equals(Object other) {
return equalsIdOrFields(this, other,
(that) -> Objects.equals(field1, that.field1) &&
Objects.equals(field2, that.field2));
}
@Override
public int hashCode() {
return hashIdOrFields(id, field1, field2);
}
First you need an interface for classes that have ID's. I call it "ID'd" or:
interface Idd {
public long getId();
}
Add methods like the following in the Utils class in your project and import them where you implement .equals() and .hashCode()
/**
* Given `this` and `other` from your equals method, checks referential equality,
* successful cast, and comparison by ID before running through any additional tests you pass in.
*/
public static <T extends Idd> boolean equalsIdOrFields(
@NotNull T orig,
@Nullable Object other,
@NotNull Predicate<T> tests) {
if (orig == other) {
return true;
}
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) orig.getClass();
if ( !clazz.isInstance(other) ) {
return false;
}
// Now it's safe to cast.
@SuppressWarnings("unchecked")
final T that = (T) other;
// If both objects have surrogate keys assigned,
// just compare them and be done.
if ( (orig.getId() != 0) && (that.getId() != 0) ) {
return (orig.getId() == that.getId());
}
// Now do class-specific tests
return tests.test(that);
}
/**
* Given the surrogate key and important fields, returns an appropriate hashCode.
*/
public static int hashIdOrFields(long id, Object... fields) {
if (id == 0) {
return Arrays.hashCode(fields);
}
// return (possibly truncated) surrogate key
return (int) id;
}
For a better explanation of what's going on here, see: My previous post