Ответ 1
Для тех из нас, кто использует Java 8, Collection#stream()
- это чистая опция:
collection.stream().anyMatch(x -> x == key)
Метод Collection.contains() проверяет, содержит ли коллекция данный объект, используя метод .equals()
для выполнения сравнения.
Из Java7 Javadoc:
boolean содержит (Object o)
Возвращает true, если эта коллекция содержит указанный элемент. Более формально возвращает true тогда и только тогда, когда коллекция содержит хотя бы один элемент e такой, что (o == null? e == null: o.equals(e)).
Есть ли разумный способ проверить, содержит ли коллекция объект o
, но вместо сравнения вместо него (т.е. o==e
)?
Конечно, я могу перебирать коллекцию и делать чек, я ищу существующую функцию, которая может это сделать.
Разъяснения:
equals()
объекта в коллекции.Edit:
Несмотря на то, что мой вопрос касается общего решения для реализаций Collection
, также будут оценены конкретные случаи для суб-интерфейсов Collection
.
Для тех из нас, кто использует Java 8, Collection#stream()
- это чистая опция:
collection.stream().anyMatch(x -> x == key)
Существует какое-то обходное решение...
Вы можете использовать IdentityHashMap
, а Void
- как значения (или что-то еще - ваш выбор). Затем вы использовали contains()
на .keySet()
, чтобы проверить наличие элемента (или .containsKey()
на карте напрямую).
Вторым обходным решением будет использование Guava и Equivalence.identity()
; однако ваш Collection
должен иметь элементы типа Equivalence.Wrapper<X>
, и вам нужно будет wrap
перед проверкой...
Любопытно, что JDK не предоставляет IdentityHashSet
. Это довольно странно, учитывая, что внутренняя реализация HashSet
использует HashMap
, поэтому нужно задаться вопросом, почему они не сделали то же самое для IdentityHashMap
...
Боковое примечание: документация Collection
вводит в заблуждение; не все реализации Collection
полагаются на .equals()
. См., Например, SortedSet
или SortedMap
. И, конечно, IdentityHashMap
.
Нет способа проверить, что вы пытаетесь сделать. Без повторения с помощью коллекции вы не можете проверить, что объект указывает на ту же ссылку или нет.
AFAIK, Нет (по крайней мере, чистый путь).
В ответах указывается, что невозможно выполнить желаемую проверку.
Итак, это возможная реализация такой запрошенной функции:
/**
* 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;
}
Примечание:
это может быть оптимизировано для некоторых конкретных реализаций Collection
.
При создании класса вы должны переопределить методы equals
(и hashCode
).
Если вы реализуете свой метод equals
для сравнения по ссылке, вы достигнете своей цели.
Вы можете сделать это, обернув объект в свой собственный объект, который реализует equals
, который вы ищете.
Что-то вроде:
private class Identical<T> {
final T held;
Identical (T hold) {
held = hold;
}
public boolean equals(Object it) {
return it != null && held == it;
}
}
Очевидно, вам придется взять под контроль добавление элементов в коллекцию и обернуть их в один из них.
Вы можете обернуть карту следующим образом:
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;
}
}