Reputation: 5498
The Collection.contains() method check if a collection contains a given object, using the .equals()
method to perform the comparison.
From Java7 Javadoc:
boolean contains(Object o)
Returns true if this collection contains the specified element. More formally, returns true if and only if this collection contains at least one element e such that (o==null ? e==null : o.equals(e)).
Is there a smart way to check if a collection contains an object o
, but comparing by reference instead (i.e. o==e
)?
Of course I can iterate through the collection and make the check, I'm looking for an existing function which can do that.
Clarifications:
equals()
implementation of the object in the collection.Edit:
Even though my question is about a general solution for Collection
implementations, specific cases for Collection
sub-interfaces would also be appreciated.
Upvotes: 29
Views: 48899
Reputation: 129507
For those of us using Java 8, Collection#stream()
is a clean option:
collection.stream().anyMatch(x -> x == key)
Upvotes: 43
Reputation: 65811
You should be able to do it by wrapping the object in your own object which implements the equals
you are looking for.
Something like:
private class Identical<T> {
final T held;
Identical (T hold) {
held = hold;
}
public boolean equals(Object it) {
return it != null && held == it;
}
}
Obviously you would have to take control of adding items to the collection and wrap each one in one of these.
You could wrap the map like this:
static class ReferenceHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V> {
private final Map<K, Identical<V>> map = new HashMap<>();
private static class Identical<T> {
final T held;
Identical(T hold) {
held = hold;
}
@Override
public boolean equals(Object it) {
return it != null && held == it;
}
@Override
public int hashCode() {
return held.hashCode();
}
}
@Override
public V get(Object key) {
Identical<V> value = map.get(key);
return value == null ? null : value.held;
}
@Override
public V put(K key, V value) {
Identical<V> replaced = map.put(key, new Identical<>(value));
return replaced == null ? null : replaced.held;
}
private class MyEntry implements Map.Entry<K, V> {
private final K key;
private V value;
public MyEntry(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
V old = this.value;
this.value = value;
return old;
}
}
@Override
public Set<Entry<K, V>> entrySet() {
Set<Entry<K, V>> entries = new HashSet<>();
for (Entry<K, Identical<V>> entry : map.entrySet()) {
entries.add(new MyEntry(entry.getKey(), entry.getValue().held));
}
return entries;
}
}
Upvotes: 0
Reputation: 5498
The answers point out that it is not possible in a clean way to perform the desired check.
So this is a possible implementation of such requested function:
/**
* Returns {@code true} if the collection contains the specified element.
* <p>
* More formally, returns {@code true} if and only if this collection
* contains at least one element {@code x} such that {@code x == element}.
* <p>
* Note: {@link Collection#contains(Object)} works differently because uses
* {@link Object#equals(Object)} for comparison
*
* @param collection
* collection where to look for the element
* @param element
* element whose presence in this collection is to be tested
* @return {@code true} if this collection contains the specified element
* @throws NullPointerException
* if {@code collection} is null
*/
public static <T> boolean containsReferenceTo(Collection<T> collection,
T element) {
if (collection == null)
throw new NullPointerException("collection cannot be null");
for (T x : collection) {
if (x == element) {
return true;
}
}
return false;
}
NOTE:
this may be optimized for some specific Collection
implementations.
Upvotes: 2
Reputation: 121710
There is some kind of workaround...
You can use an IdentityHashMap
, with Void
as values (or whatever else -- your choice). You'd then use contains()
on its .keySet()
to check the presence of an element (or .containsKey()
on the map directly).
A second workaround would be to use Guava and Equivalence.identity()
; however your Collection
will have to have elements of type Equivalence.Wrapper<X>
and you'd have to wrap
before checking...
Curiously enough, the JDK does not provide an IdentityHashSet
. This is rather strange considering that the internal implementation of HashSet
uses a HashMap
, so one has to wonder why they didn't do the same for IdentityHashMap
...
Side note: the documentation of Collection
is misleading; not all Collection
implementations rely on .equals()
. See, for instance, SortedSet
or SortedMap
. And, of course, IdentityHashMap
.
Upvotes: 11
Reputation: 121998
There is no way to check that the way you are trying to do. Without iterating through collection you cannot check that the object point to same reference or not.
AFAIK, No (At least a clean way).
Upvotes: 3
Reputation: 3353
When you create a class you should override at least equals
(and hashCode
) methods.
If you implement your equals
method to compare by reference you will achieve your goal.
Upvotes: 2