Поток против итераторов в множестве
Насколько я понимаю, следующий код должен напечатать 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);
3 ответа
Обе записи относятся к одной и той же логической записи вашей Карты (ключ которой "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()
вернуть тот же экземпляр.
Дело в том:
Map.Entry<String, String> entry1 = set.iterator().next();
Map.Entry<String, String> entry2 = set.stream().findFirst().get();
Вы не сравниваете значения, которые вы положили в карту. Но входные объекты!
Другими словами: похоже, ваш код создает новые объекты Entry, используя ваш код. Это полностью зависит от внутренней реализации этого неизменяемого Map/Set, что возвращать, когда его просят об итераторе или потоке... и поскольку Эран был немного быстрее искать: причина в том, что новые объекты Entry создаются, когда итерация
Итак, при использовании equals()
вместо ==
... вы получите ожидаемый результат.
Нет обоих 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()
даст хэш-код.