迭代 EnumMap 不会导致每次迭代都创建新对象

Iterate over an EnumMap which doesn't lead to a new object creation per iteration

有没有一种方法可以迭代 EnumMap 而不会导致每次迭代都创建新对象? entryset 的迭代器 returns 每次都是一个新的 Entry。我能看到的唯一方法是

for(K k: map.keySet()) 
    foo(k, map.get(k));

澄清这是关于 EnumMap 的,它在其 EntrySet 上有以下迭代器实现

 public Map.Entry<K,V> next() {
        if (!hasNext())
            throw new NoSuchElementException();
        lastReturnedEntry = new Entry(index++);
        return lastReturnedEntry;
    }

首先,您的代码并不是每次都创建一个对象。它仅获得对现有对象的 引用

是的,有更好的方法:

for (Map.Entry<K, V> entry : map.entrySet()) {
    // use entry.getKey() and entry.getValue()
}

或Java8版本:

map.forEach((k, v) -> {...});

我本能地怀疑这种对对象创建的关注的合法性。但是,如果避免对象创建真的如此重要,您可以维护自己的枚举常量数组并为每个数组测试 map.contains(...)。您必须对此进行测试以查看性能比较。

首先,从您所说的看来,您希望迭代器 return 两个对象的元组。

在 Java 中,唯一的方法是将它们包装在另一个对象中。 (在撰写本文时,就是这样。)所以迭代器必须 return 除了键和值之外的对象。该对象必须在调用 next() returns.

之前的某个时刻创建

考虑到这一限制,可以采取三种合理的途径:

  1. put() 上创建此条目对象。
  2. entrySet() 的第一次迭代中创建条目对象(但之后缓存它)。
  3. entrySet() 的每次迭代中创建一个新的条目对象。

built-in EnumMap 选择选项 3 的可能原因是它最容易实现,而且如果您不需要遍历条目,它是最经济的解决方案。缺点是如果你需要多次迭代,你创建的对象比任何其他解决方案都多。

选项 1 实施起来同样简单,但每次向地图添加条目时都会产生明显的开销,即使您从未打算访问它也是如此。

最后,选项 2 涉及稍微复杂的代码,以及在迭代和添加更多元素之间交替时的一些边缘情况,但它为您提供理论上最好的内存配置文件。

如果多次迭代的内存开销被证明是您的应用程序中的一个问题,您可以轻松地实施选项 2,但我怀疑在大多数情况下差异是否会很明显。

P.s.: 如果您愿意偏离惯用的解决方案并进入稍微疯狂的领域,您可以 re-use 所有条目的相同 Map.Entry 实例。这显然与我们对 Map.Entry 的期望相矛盾,但它为您提供了最小的内存分配开销,并且您可以在简单的迭代场景中摆脱它。是否最终得到更快的最终产品是任何人的猜测,您需要对其进行衡量。