T
- type of objects compared by this equivalencepublic abstract class Equivalence<T> extends Object
This class is inspired and very similar to
Guava's Equivalence
, with one notable difference: this Equivalence
forces
the actual implementation to override equals(Object)
and hashCode()
. Notice
these are Equivalence
's own equals and hashCode, not the strategy
equivalent(Object, Object)
and hash(Object)
methods. It is needed because,
for example, ObjCollection
's equality depends on Equivalence
equality.
In most cases, when Equivalence
is stateless, you can extend
StatelessEquivalence
not to bother with implementing these methods. See examples
in the documentation to identity and
case insensitive equivalences.
Modifier | Constructor and Description |
---|---|
protected |
Equivalence()
Constructor for use by subclasses.
|
Modifier and Type | Method and Description |
---|---|
static Equivalence<String> |
caseInsensitive()
Returns the
String equivalence that uses String.equalsIgnoreCase(java.lang.String) to compare
strings. |
static <T> Equivalence<T> |
defaultEquality()
Returns the default, built-in equivalence in Java, driven by
Object.equals(Object)
and Object.hashCode() methods. |
static <K,V> Equivalence<Map.Entry<K,V>> |
entryEquivalence(Equivalence<K> keyEquivalence,
Equivalence<V> valueEquivalence)
Returns a
Map.Entry equivalence for the given key and value equivalences. |
abstract boolean |
equals(Object o)
Indicates whether some other object is "equal to" this one.
|
abstract boolean |
equivalent(T a,
T b)
Returns
true if a and b are considered equivalent,
false otherwise. |
abstract int |
hash(T t)
Returns a hash code for the given object.
|
abstract int |
hashCode()
Returns a hash code value for the object.
|
static <T> Equivalence<T> |
identity()
Returns the equivalence that uses
== to compare objects and
System.identityHashCode(Object) to compute the hash code. |
boolean |
nullableEquivalent(T a,
T b)
Returns
true if a and b are considered equivalent,
false otherwise. |
int |
nullableHash(T t)
Returns a hash code for the given object.
|
@Nonnull public static <T> Equivalence<T> defaultEquality()
Object.equals(Object)
and Object.hashCode()
methods.T
- type of objects, needed to compare. Object.equals(java.lang.Object)
could be applied to
object of any type, so there aren't any constraints over the generic type parameter.@Nonnull public static <T> Equivalence<T> identity()
==
to compare objects and
System.identityHashCode(Object)
to compute the hash code.
nullableEquivalent(T, T)
returns true
if a == b
, including
in the case when a
and b
are both null
.
This equivalence could be implemented as follows:
final class Identity extends StatelessEquivalence<Object> {
static final Identity INSTANCE = new Identity();
private Identity() {}
@Override
public boolean equivalent(@Nonnull Object a, @Nonnull Object b) {
return a == b;
}
@Override
public int hash(@Nonnull Object t) {
return System.identityHashCode(t);
}
}
T
- type of objects, needed to compare. Identity check could be applied to objects
of any type, so there aren't any constraints over the generic type parameter.@Nonnull public static Equivalence<String> caseInsensitive()
String
equivalence that uses String.equalsIgnoreCase(java.lang.String)
to compare
strings.
This equivalence could be implemented as follows:
final class CaseInsensitive extends StatelessEquivalence<String> {
static final CaseInsensitive INSTANCE = new CaseInsensitive();
private CaseInsensitive() {}
@Override
public boolean equivalent(@Nonnull String a, @Nonnull String b) {
return a.equalsIgnoreCase(b);
}
@Override
public int hash(@Nonnull String s) {
return s.toLowerCase().hashCode();
}
}
String
equivalence@Nonnull public static <K,V> Equivalence<Map.Entry<K,V>> entryEquivalence(@Nonnull Equivalence<K> keyEquivalence, @Nonnull Equivalence<V> valueEquivalence)
Map.Entry
equivalence for the given key and value equivalences.K
- the entry key typeV
- the entry value typekeyEquivalence
- the entry key equivalencevalueEquivalence
- the entry value equivalenceMap.Entry
equivalence for the given key and value equivalencespublic boolean nullableEquivalent(@Nullable T a, @Nullable T b)
true
if a
and b
are considered equivalent,
false
otherwise. a
and b
both might be null
.
If the implementation overrides this method, it must ensure that it returns
true
if both the given objects are nulls and false
, if only one of them
is null
. If both a
and b
are non-null, this method should perform
just the same as equivalent(Object, Object)
method does.
a
- the first object to compareb
- the second object to comparetrue
if a
and b
are considered equivalent,
false
otherwisepublic abstract boolean equivalent(@Nonnull T a, @Nonnull T b)
true
if a
and b
are considered equivalent,
false
otherwise. a
and b
are assumed to be non-null.
This method implements an equivalence relation on object references:
x
, equivalent(x, x)
returns true
.
x
and y
,
equivalent(x, y) == equivalent(y, x)
.
x
, y
, and z
,
if equivalent(x, y)
returns true
and equivalent(y, z)
returns
true
, then equivalent(x, z)
returns true
.
x
and y
, multiple invocations
of equivalent(x, y)
consistently return true
or consistently return
false
(provided that neither x
nor y
is modified).
This method is called by nullableEquivalent(Object, Object)
.
a
- the first object to compareb
- the second object to comparetrue
if a
and b
are considered equivalent,
false
otherwisepublic int nullableHash(@Nullable T t)
t
object might be null
.
If the implementation overrides this method, it must ensure that it returns
0
if the given object is null
. Otherwise this method should perform just
the same as hash(Object)
method does.
t
- the object to compute hash code forpublic abstract int hash(@Nonnull T t)
t
object is assumed to be non-null.
This method has the following properties:
x
, multiple invocations of
hash(x)
consistently return the same value provided x
remains unchanged
according to the definition of the equivalence. The hash need not remain consistent from
one execution of an application to another execution of the same application.
x
and
y
, if equivalent(x, y)
, then hash(x) == hash(y)
. It is not
necessary that the hash be distributable across inequivalence.
If equivalence(x, y)
is false, hash(x) == hash(y)
may still be true.
This method is called by nullableHash(Object)
.
t
- the object to compute hash code forpublic abstract boolean equals(Object o)
The equals
method implements an equivalence relation
on non-null object references:
x
, x.equals(x)
should return
true
.
x
and y
, x.equals(y)
should return true
if and only if
y.equals(x)
returns true
.
x
, y
, and z
, if
x.equals(y)
returns true
and
y.equals(z)
returns true
, then
x.equals(z)
should return true
.
x
and y
, multiple invocations of
x.equals(y)
consistently return true
or consistently return false
, provided no
information used in equals
comparisons on the
objects is modified.
x
,
x.equals(null)
should return false
.
The equals
method for class Object
implements
the most discriminating possible equivalence relation on objects;
that is, for any non-null reference values x
and
y
, this method returns true
if and only
if x
and y
refer to the same object
(x == y
has the value true
).
Note that it is generally necessary to override the hashCode
method whenever this method is overridden, so as to maintain the
general contract for the hashCode
method, which states
that equal objects must have equal hash codes.
This method is made abstract
to force the final implementation to override it.
It is needed because, for example, ObjObjMap
's
equality depends on key and value Equivalence
equality.
equals
in class Object
o
- the reference object with which to compare.true
if this object is the same as the obj
argument; false
otherwise.Object.hashCode()
,
HashMap
public abstract int hashCode()
HashMap
.
The general contract of hashCode
is:
hashCode
method
must consistently return the same integer, provided no information
used in equals
comparisons on the object is modified.
This integer need not remain consistent from one execution of an
application to another execution of the same application.
equals(Object)
method, then calling the hashCode
method on each of
the two objects must produce the same integer result.
Object.equals(java.lang.Object)
method, then calling the hashCode
method on each of the
two objects must produce distinct integer results. However, the
programmer should be aware that producing distinct integer results
for unequal objects may improve the performance of hash tables.
As much as is reasonably practical, the hashCode method defined by
class Object
does return distinct integers for distinct
objects. (This is typically implemented by converting the internal
address of the object into an integer, but this implementation
technique is not required by the
JavaTM programming language.)
This method is made abstract
to force the final implementation to override it.
It is needed because, equals(Object)
is needed to be overridden, and in Java
Object.equals(Object)
and Object.hashCode()
should always
be overridden simultaneously.
hashCode
in class Object
Object.equals(java.lang.Object)
,
System.identityHashCode(java.lang.Object)