Поток против итераторов в множестве

Насколько я понимаю, следующий код должен напечатать 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() даст хэш-код.

Другие вопросы по тегам