Java 在不';t导致每次迭代都创建一个新对象

Java 在不';t导致每次迭代都创建一个新对象,java,keyset,enum-map,Java,Keyset,Enum Map,有没有一种方法可以在EnumMap上迭代,而每次迭代都不会创建新的对象?entryset的迭代器每次都返回一个新条目。我唯一能看到的是 for(K k: map.keySet()) foo(k, map.get(k)); 为了澄清这一点,我们特别介绍了EnumMap,它的EntrySet上有以下迭代器实现 public Map.Entry<K,V> next() { if (!hasNext()) throw new NoSuch

有没有一种方法可以在EnumMap上迭代,而每次迭代都不会创建新的对象?entryset的迭代器每次都返回一个新条目。我唯一能看到的是

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;
    }
public Map.Entry next(){
如果(!hasNext())
抛出新的NoTouchElementException();
lastReturnedEntry=新条目(索引++);
返回lastReturnedEntry;
}

首先,您的代码不会每次都创建对象。它只获取对现有对象的引用

是的,有更好的方法:

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

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

首先,从您所说的内容来看,您似乎希望迭代器返回两个对象的元组

在Java中,实现这一点的唯一方法是将它们包装到另一个对象中。(即在编写时)因此迭代器必须返回键和值以外的对象。在调用
next()
返回之前,必须在某个点创建该对象

考虑到这一限制因素,有三条可行的路径可供选择:

  • put()
    上创建此条目对象
  • 在跨
    entrySet()
    的第一次迭代中创建entry对象(但随后将其缓存)
  • entrySet()
    的每次迭代中创建一个新的条目对象
  • 内置的
    EnumMap
    之所以选择选项3,可能是因为它最容易实现,而且如果不需要遍历条目,它也是最经济的解决方案。缺点是,如果需要多次迭代,则创建的对象比任何其他解决方案都多

    选项1的实现同样简单,但每次向地图添加条目时都会有明显的开销,即使您从未打算访问它

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

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


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

    我在这里特别谈论EnumMap。entrySet迭代器类似于以下公共映射。Entry next(){如果(!hasNext())抛出新的NoSuchElementException();lastReturnedEntry=new Entry(index++);return lastReturnedEntry;}是,对象创建是否存在问题不是问题。我正在寻找一种惯用的方法来实现这一点,而不必求助于保留枚举数组。为什么必须保留枚举数组?@marstran因为没有一种形式的
    EnumMap#contains(…)
    接受常量的
    int
    ordinal。那么您自己的解决方案有什么不好的地方呢?
    为什么(V值:map.values())foo(值)
    ?除了检索值之外,您似乎没有在使用这些键。@VGR fair point。我也需要这个键。这样的话,您就不走运了。您可以编写自己的EnumMap实现来实现它,不过如果您需要返回键和值,但不创建新对象,您的解决方案将我肯定不是惯用的。@realpoint是的,我目前的方法还不错。我很惊讶地发现EnumMap实现即使在Java 8中也没有很好的foreach覆盖。只是在这里确认我的理解,并检查是否有更好的方法。
    map.forEach((k, v) -> {...});