Java foreach 是否创建副本?

Does Java foreach create copies?

我有一个关于这个 foreach 的问题:

    for(Element e : nullProof(setOfElements)){
            // do stuff
    }

假设我将函数 nullProof 定义为 return 一个 non-null 集合(因为我听说你不应该将 null 传递给增强的 for-loop。这是真的吗? ):

    private Set<Element> nullProof(Set<Element> s){
          return s == null ? Collections.<Element> emptySet() : s;
    }

我的问题是...在 foreach 中调用 nullProof 函数安全吗?具体来说,下面的header是否等同于:

    for(Element e : setOfElements){    //assuming setOfElements != null

我想知道是否有人可以指出一些 Java 标准,该标准表明这是定义的行为。

此外,有人可以解释一下调用这个 foreach 时 "behind the scenes" 实际发生了什么吗?

假设 setOfElements 的大小为 6。对于通过 setOfElements 的每次迭代,JVM 是否查找 setOfElements 6 次不同的时间,还是创建该集合的副本并引用该副本?我试图理解这种行为。感谢您的帮助!

是的,它非常安全。

for(Element e :  nullProof(setOfElements)) {

等同于

Set<Element> s = nullProof(setOfElements);
for(Element e :  s) {

JLS-14 所述,幕后 for each 循环等同于:

for(Iterator<Element> it = s.iterator() ; it.hasNext() ; ) {
    Element e = it.next();
    // ...
}

这是安全的,因为在任何迭代发生之前必须解析实际的集合,但它在某种程度上掩盖了您的意图。在我看来,这更清楚:

if (setOfElements != null) {
    for (Element e : setOfElements) {
        ...
    }
}

或者,您可能想要重新评估 为什么 您允许 setOfElements 成为 null。首先将它设为空列表是否有意义,而不是 null?


Let's say setOfElements has size 6. For each iteration through setOfElements, does the JVM look up setOfElements 6 different times, or does it create a copy of that set and refer to the copy? I'm trying to understand the behavior.

不涉及复制。增强的 for 循环使用 Iterator (as returned by the iterator method of any collection) to do its iteration. An Iterator is an object that is able to give you the elements of some collection one by one through its next 方法。