Java foreach效率

时间:2009-05-24 20:30:57

标签: java performance loops foreach premature-optimization

我有这样的事情:

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

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

在{strong> foreach循环中调用一次myMap.keySet()是什么? 我想是的,但想要你的意见。

我想知道以这种方式使用foreach(myMap.keySet())是否会对性能产生影响,或者它与此相同:

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

6 个答案:

答案 0 :(得分:65)

如果你想要绝对肯定,那么就两种方式进行编译并反编译并进行比较。我使用以下来源做到了这一点:

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));
  }
}

当我用Jad反编译类文件时,我得到:

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);
    }
}

所以这是你的答案。它以for-loop形式调用一次。

答案 1 :(得分:35)

它只被召唤一次。实际上它使用迭代器来完成这个技巧。

此外,在您的情况下,我认为您应该使用

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

每次都避免在地图中搜索。

答案 2 :(得分:9)

keySet()只被调用一次。 “增强的for循环”基于Iterable接口,它用于获取Iterator,然后将其用于循环。甚至不可能以任何其他方式迭代Set,因为没有索引或任何可以获取单个元素的东西。

然而,你真正应该做的是完全放弃这种微优化的担忧 - 如果你遇到真正的性能问题,那么你自己从未想过的东西大约有99%。

答案 3 :(得分:7)

答案在Java语言规范中,不需要反编译:)这是我们可以阅读的关于the enhanced for statement的内容:

  

增强的for语句有   形式:

EnhancedForStatement:
        for ( VariableModifiersopt Type Identifier: Expression) Statement
     

Expression必须具有类型   Iterable或者它必须是   数组类型(第10.1节),或编译时   发生错误。

     

声明的局部变量的范围   在FormalParameter中的一部分   增强的for声明(§14.14)是   包含的声明

     

增强型for的含义   声明是通过翻译给出的   一个基本的for陈述。

     

如果 Expression 的类型是a   Iterable的子类型,然后让 I 成为   表达式的类型   表达。 iterator()。增强的for语句是等效的   到...的基本for陈述   形式:

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

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

#i 是编译器生成的   与任何不同的标识符   其他标识符(编译器生成的   或者在其他方面)在范围内(§6.3)   在增强的点   声明发生。

     

否则,表达必然   有一个数组类型, T[] 。让 L1 ... Lm   是(可能是空的)序列   紧接着之前的标签   增强的for声明。那么   增强的for语句的含义   由以下基本for给出   语句:

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

其中 a i 是编译器生成的   与任何不同的标识符   其他标识符(编译器生成的   或者其他)在范围内   点在哪里增强for语句   发生。

在您的情况下,myMap.keySet()会返回Iterable的子类型,因此您的增强型for语句等同于以下基本for语句:

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

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

因此myMap.keySet()只被调用一次。

答案 4 :(得分:5)

是的,它只会被调用一次

答案 5 :(得分:-2)

我相信它的编译器经过优化,每个循环条目只运行一次。