Поток против Итератора в entrySet Карты
Насколько я понимаю, следующий код должен вывести true
, так как Stream
и Iterator
указывают на первый элемент.
Однако, когда я запускаю следующий код, он печатает false
:
final HashMap<String, String> map = new HashMap<>();
map.put("A", "B");
final Set<Map.Entry<String, String>> set = Collections.unmodifiableMap(map).entrySet();
Map.Entry<String, String> entry1 = set.iterator().next();
Map.Entry<String, String> entry2 = set.stream().findFirst().get();
System.out.println(entry1 == entry2);
В чем причина разного поведения?
Ответы
Ответ 1
Обе записи ссылаются на одну и ту же логическую запись вашей Карты (чей ключ "A", а значение "B" ). Однако они не являются тем же самым экземпляром.
Если вы выровняете достаточно глубоко в реализации Collections.unmodifiableMap(map)
, вы увидите, что итерация по entrySet
на карте, возвращаемой Collections.unmodifiableMap(map)
, возвращает новый Map.Entry
, который обертывает исходную модифицируемую запись:
public Map.Entry<K,V> next() {
return new UnmodifiableEntry<>(i.next());
}
Я предполагаю, что экземпляр экземпляра Map.Entry
создается также при вызове set.stream().findFirst().get()
, поэтому два метода возвращают разные экземпляры.
Даже если вы вызовете тот же метод дважды, вы получите разностные экземпляры, т.е. следующий код также напечатает false
:
Map.Entry<String, String> entry1 = set.iterator().next();
Map.Entry<String, String> entry2 = set.iterator().next();
System.out.println(entry1 == entry2);
С другой стороны, если вы получите запись непосредственно из оригинала HashMap
, вы получите true
:
Map.Entry<String, String> entry1 = map.entrySet ().iterator().next();
Map.Entry<String, String> entry2 = map.entrySet ().stream().findFirst().get();
System.out.println (entry1==entry2);
Если в этом случае запись не завершается новым экземпляром, так что оба entrySet ().iterator().next()
и entrySet ().stream().findFirst().get()
возвращают один и тот же экземпляр.
Ответ 2
Дело в том, что
Map.Entry<String, String> entry1 = set.iterator().next();
Map.Entry<String, String> entry2 = set.stream().findFirst().get();
Вы не сравниваете значения , которые вы положили на карту. Но Ввод объектов!
Другими словами: похоже, что ваш код создает объекты new Entry, используя ваш код. Это полностью зависит от внутренней реализации этой немодифицируемой Карты/Установить, что нужно вернуть, когда ее запрашивают итератор или поток... и поскольку Эран был немного быстрее в поиске: причина в том, что новый Объекты ввода создаются при итерации.
Итак, при использовании equals()
вместо ==
... вы получите ожидаемый результат.
Ответ 3
Оба параметра entry1
и entry2
имеют одинаковое значение, но они не указывают один и тот же объект, потому что каждый раз, когда вы получаете объект Map.Entry
, он создает новый.
Посмотрите на приведенный ниже код:
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Test1 {
public static void main(String[] args) {
final HashMap<String, String> map = new HashMap<>();
map.put("A", "B");
final Set<Map.Entry<String, String>> set = Collections.unmodifiableMap(map).entrySet();
Map.Entry<String, String> entry1 = set.iterator().next();
Map.Entry<String, String> entry2 = set.stream().findFirst().get();
System.out.println("entry1 : " + System.identityHashCode(entry1));
System.out.println("entry2 : " + System.identityHashCode(entry2));
for (int i = 0; i < 5; i++) {
System.out.println("directly for set " + i + " : " + System.identityHashCode(set.stream().findFirst().get()));
}
}
}
Вывод:
entry1 : 1283928880
entry2 : 295530567
directly for set 0 : 2003749087
directly for set 1 : 1324119927
directly for set 2 : 990368553
directly for set 3 : 1096979270
directly for set 4 : 1078694789
System.identityHashCode()
выдаст хэш-код.