Java foreach efficiency

随声附和 提交于 2019-11-27 12:15:12

问题


I have something like this:

Map<String, String> myMap = ...;

for(String key : myMap.keySet()) {
   System.out.println(key);
   System.out.println(myMap.get(key)); 
}

So is myMap.keySet() called once in the foreach loop? I think it is, but want your opinion.

I would like to know if using foreach in this way (myMap.keySet()) has a performance impact or it is equivalent to this:

Set<String> keySet = myMap.keySet();
for (String key : keySet) {
   ...
}

回答1:


If you want to be absolutely certain, then compile it both ways and decompile it and compare. I did this with the following source:

public void test() {
  Map<String, String> myMap = new HashMap<String, String>();

  for (String key : myMap.keySet()) {
    System.out.println(key);
    System.out.println(myMap.get(key));
  }

  Set<String> keySet = myMap.keySet();
  for (String key : keySet) {
    System.out.println(key);
    System.out.println(myMap.get(key));
  }
}

and when I decompiled the class file with Jad, I get:

public void test()
{
    Map myMap = new HashMap();
    String key;
    for(Iterator iterator = myMap.keySet().iterator(); iterator.hasNext(); System.out.println((String)myMap.get(key)))
    {
        key = (String)iterator.next();
        System.out.println(key);
    }

    Set keySet = myMap.keySet();
    String key;
    for(Iterator iterator1 = keySet.iterator(); iterator1.hasNext(); System.out.println((String)myMap.get(key)))
    {
        key = (String)iterator1.next();
        System.out.println(key);
    }
}

So there's your answer. It is called once with either for-loop form.




回答2:


It's only called once. In fact it uses an iterator to do the trick.

Furthermore, in your case, I think you should use

for (Map.Entry<String, String> entry : myMap.entrySet())
{
    System.out.println(entry.getKey());
    System.out.println(entry.getValue());
}

to avoid searching in the map each time.




回答3:


keySet() is called only once. The "enhanced for loop" is based on the Iterable interface, which it uses to obtain an Iterator, which is then used for the loop. It's not even possible to iterate over a Set in any other way, since there is no index or anything by which you could obtain individual elements.

However, what you really should do is abandon this kind of micro-optimization worries entirely - if you ever have real performance problems, the chance is about 99% that it's something you'd never thought about on your own.




回答4:


The answer is in the Java Language Specification, not need to decompile :) This is what we can read about the enhanced for statement:

The enhanced for statement has the form:

EnhancedForStatement:
        for ( VariableModifiersopt Type Identifier: Expression) Statement

The Expression must either have type Iterable or else it must be of an array type (§10.1), or a compile-time error occurs.

The scope of a local variable declared in the FormalParameter part of an enhanced for statement (§14.14) is the contained Statement

The meaning of the enhanced for statement is given by translation into a basic for statement.

If the type of Expression is a subtype of Iterable, then let I be the type of the expression Expression.iterator(). The enhanced for statement is equivalent to a basic for statement of the form:

for (I #i = Expression.iterator(); #i.hasNext(); ) {

        VariableModifiersopt Type Identifier = #i.next();
   Statement
}

Where #i is a compiler-generated identifier that is distinct from any other identifiers (compiler-generated or otherwise) that are in scope (§6.3) at the point where the enhanced for statement occurs.

Otherwise, the Expression necessarily has an array type, T[]. Let L1 ... Lm be the (possibly empty) sequence of labels immediately preceding the enhanced for statement. Then the meaning of the enhanced for statement is given by the following basic for statement:

T[] a = Expression;
L1: L2: ... Lm:
for (int i = 0; i < a.length; i++) {
        VariableModifiersopt Type Identifier = a[i];
        Statement
}

Where a and i are compiler-generated identifiers that are distinct from any other identifiers (compiler-generated or otherwise) that are in scope at the point where the enhanced for statement occurs.

In your case, myMap.keySet() returns a subtype of Iterable so your enhanced for statement is equivalent to the following basic for statement:

for (Iterator<String> iterator = myMap.keySet().iterator(); iterator.hasNext();) {
   String key = iterator.next();

   System.out.println(key);
   System.out.println(myMap.get(key)); 
}

And myMap.keySet() is thus called only once.




回答5:


Yes, it's called only once either way




回答6:


I believe it's compiler optimized to run only once per loop entry.



来源:https://stackoverflow.com/questions/904582/java-foreach-efficiency

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!