在Map的entrySet中流与Iterator

Jok*_*ker 19 java iterator java-8 java-stream entryset

据我了解,下面的代码应打印true,因为两者StreamIterator指向的第一个元素.

但是,当我运行以下代码时,它正在打印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);
Run Code Online (Sandbox Code Playgroud)

不同行为的原因是什么?

Era*_*ran 32

两个条目都指向Map的相同逻辑条目(其键为"A",值为"B").但是,它们不是同一个实例.

如果你在实现中深入挖掘,Collections.unmodifiableMap(map)你将会看到迭代entrySet返回的map Collections.unmodifiableMap(map)返回一个新的Map.Entry包装原始可修改的条目:

public Map.Entry<K,V> next() {
  return new UnmodifiableEntry<>(i.next());
}
Run Code Online (Sandbox Code Playgroud)

我假设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);
Run Code Online (Sandbox Code Playgroud)

另一方面,如果您直接从原件获得该条目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);
Run Code Online (Sandbox Code Playgroud)

如果这种情况下,条目不通过一个新的实例包裹,所以无论entrySet ().iterator().next()entrySet ().stream().findFirst().get()返回同一个实例.

  • 感谢在next()中找到该行.我也做了一些搜索,但很快就放弃了.修复了凌乱的缩进btw ;-) (2认同)
  • 很好的发现.似乎这个问题与stream vs iterator无关,但是,它与unmodifiableMap实现有关. (2认同)

Gho*_*ica 11

事情是:

Map.Entry<String, String> entry1 = set.iterator().next();
Map.Entry<String, String> entry2 = set.stream().findFirst().get();
Run Code Online (Sandbox Code Playgroud)

您没有比较放入地图的.但是Entry对象!

换句话说:看起来您的代码正在使用您的代码创建新的 Entry对象.这完全取决于那个不可修改的Map/Set 的内部实现,当它被要求一个迭代器或一个流时返回什么...并且因为Eran查找起来要快一点:原因是当创建新的 Entry对象时迭代.

因此,当使用equals()而不是==...时,您将获得预期的输出.