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 Equivalence<CharSequence> |
charSequence()
Returns the equivalence that compares
CharSequence s by their contents. |
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) |
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() |
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<CharSequence> charSequence()
CharSequence
s by their contents.
This equivalence could be implemented as follows (actual implementation, of cause, is more efficient and doesn't allocate garbage objects):
final class CharSequenceEquivalence extends StatelessEquivalence<CharSequence> {
static final CharSequenceEquivalence INSTANCE = new CharSequenceEquivalence();
private CharSequenceEquivalence() {}
@Override
public boolean equivalent(@Nonnull CharSequence a, @Nonnull CharSequence b) {
return a.toString().equals(b.toString());
}
@Override
public int hash(@Nonnull CharSequence cs) {
return cs.toString().hashCode();
}
}
CharSequence
equivalence@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)
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.
public abstract int hashCode()
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.