【问题标题】:Stream Vs. Iterator in entrySet of a Map - Java 8流与。 Map 的 entrySet 中的迭代器 - Java 8
【发布时间】:2017-06-22 06:19:42
【问题描述】:

据我了解,以下代码应该打印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);

造成这种不同行为的原因可能是什么?

【问题讨论】:

  • 不,不应该,因为 HashMap 的 entrySet 没有排序。
  • @JBNizet-- 同意,但先生,我的地图中只有 1 个元素。
  • 地图也不保证它们不会动态创建新的 Map.Entry 实例。不要用 == 比较对象。使用 equals()。
  • 我同意@JBNizet。使用“entry1.equals(entry2)”
  • @Eran-- 你也是英语专家吗...:D 非常好的编辑...(Y)

标签: java java-8 iterator java-stream entryset


【解决方案1】:

这两个条目都引用了 Map 的同一个逻辑条目(其键是“A”,值是“B”)。但是,它们不是同一个实例。

如果您在Collections.unmodifiableMap(map) 的实现中深入挖掘,您会发现遍历Collections.unmodifiableMap(map) 返回的映射的entrySet 会返回一个新的Map.Entry,该Map.Entry 包装了原始可修改条目:

public Map.Entry<K,V> next() {
  return new UnmodifiableEntry<>(i.next());
}

我假设当您调用set.stream().findFirst().get() 时还会创建一个新实例Map.Entry 实例,因此这两个方法返回不同的实例。

即使你调用同一个方法两次你也会得到不同的实例,即下面的代码也会打印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() 都返回相同的实例。

【讨论】:

  • 感谢在 next() 中找到该行。我也做了一些搜索,但很快就放弃了。修复了凌乱的缩进 btw ;-)
  • 伟大的发现。似乎这个问题与流与迭代器无关,但是,它与 unmodifiableMap 实现有关。
【解决方案2】:

事情是这样的:

Map.Entry<String, String> entry1 = set.iterator().next();
Map.Entry<String, String> entry2 = set.stream().findFirst().get();

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

换句话说:您的代码似乎正在使用您的代码创建 new Entry 对象。这完全取决于该不可修改的 Map/Set 的 internal 实现,当它被要求提供迭代器或流时要返回的内容......并且 Eran 的查找速度更快:原因是迭代时创建new条目对象。

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

【讨论】:

    【解决方案3】:

    entry1entry2 没有相同的值,但它们没有指向同一个对象,因为每次获得 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() 会给出哈希码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-16
      • 2018-07-28
      • 2022-06-18
      • 1970-01-01
      • 1970-01-01
      • 2012-03-23
      • 2015-02-11
      • 1970-01-01
      相关资源
      最近更新 更多