We've got an OO codebase where in quite a lot of cases hashcode()
and equals()
simply don't work, mostly for the following reason:
There is no way to extend an instantiable class and add a value component while preserving the equals contract, unless you are willing to forgo the benefits of object-oriented abstraction.
That's a quote from "Effective Java" by Joshua Bloch and there's more on that subject in a great Artima article here:
http://www.artima.com/lejava/articles/equality.html
And we're perfectly fine with that, this is not what this question is about.
The question is: seen that it is a fact that in some case you cannot satisfy the equals()
contract, what would be a clean way to automatically make hashcode()
and equals()
throw an UnsupportedOperationException?
Would an annotation work? I'm thinking about something like @NotNull
: every @NotNull
contract violation does throw an exception automatically and you have nothing else to do besides annotating your parameters/return value with @NotNull
.
It's convenient, because it's 8 characters ("@NotNull") instead of constantly repeating the same verification/throw exception code.
In the case that I'm concerned about, in every implementation where hashCode()/equals()
makes no sense, we're always repeating the same thing:
@Override
public int hashCode() {
throw new UnsupportedOperationException( "contract violation: calling hashCode() on such an object makes no sense" );
}
@Override
public boolean equals( Object o ) {
throw new UnsupportedOperationException( "contract violation: calling equals() on such an object makes no sense" );
}
However this is error prone: we may by mistake forget to cut/paste this and it may results in users misusing such objects (say by trying to put them in the default Java collections).
Or if annotation can't be made to create this behavior, would AOP work?
Interestingly the real issue it the very presence of hashCode()
and equals()
at the top of the Java hierarchy which simply makes no sense in quite some cases. But then how do we deal with this problem cleanly?
return null
,return false
,do nothing
. I'd like the default to bethrow UnsupportedOperationException("TODO")
. – FootedUnsupportedOperationException
– Globate.equals()
is identical to==
for classes, meaning that it checks if two variables point to the same reference. Which there is no harm to doing. – Hashum