Java foreach效率

Flu*_*dan 22 java performance foreach loops premature-optimization

我有这样的事情:

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

for(String key : myMap.keySet()) {
   System.out.println(key);
   System.out.println(myMap.get(key)); 
}
Run Code Online (Sandbox Code Playgroud)

所以myMap.keySet()foreach循环中调用一次?我想是的,但想要你的意见.

我想知道如果以这种方式使用foreach(myMap.keySet())会对性能产生影响,或者它等同于:

Set<String> keySet = myMap.keySet();
for (String key : keySet) {
   ...
}
Run Code Online (Sandbox Code Playgroud)

Edd*_*die 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));
  }
}
Run Code Online (Sandbox Code Playgroud)

当我用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

所以有你的答案.它以for-loop形式调用一次.

  • +1用于实际证明编译器的功能 (11认同)

Val*_*her 35

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

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

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

避免每次在地图中搜索.

  • 谢谢大家,分享你的智慧!我希望我的同龄人一样! (2认同)

Mic*_*rdt 9

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

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

  • "你真正应该做的是完全放弃这种微优化的担忧"他所关心的问题一般都不是微观优化...... (2认同)

Pas*_*ent 7

答案是在Java语言规范中,不需要反编译:)这是我们可以阅读的有关增强的for语句的内容:

增强的for语句具有以下形式:

EnhancedForStatement:
        for ( VariableModifiersopt Type Identifier: Expression) Statement
Run Code Online (Sandbox Code Playgroud)

Expression必须具有类型 Iterable,否则它必须是数组类型(第10.1节),否则会发生编译时错误.

在增强for语句(第14.14节)的FormalParameter部分中声明的局部变量的范围是包含的Statement

增强for 陈述的含义通过翻译成基本for陈述给出.

如果类型Expression是子类型Iterable,那么让我们I成为表达式Expression的类型 .iterator().增强for语句等同于for表单的基本语句:

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

        VariableModifiersopt Type Identifier = #i.next();
   Statement
}
Run Code Online (Sandbox Code Playgroud)

#i编译器生成的标识符在何处是与增强的for语句发生时的范围(第6.3节)中的任何其他标识符(编译器生成的或其他标识符)不同.

否则,Expression必须具有数组类型,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
}
Run Code Online (Sandbox Code Playgroud)

其中ai是编译器生成的标识符,它们与发生增强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)); 
}
Run Code Online (Sandbox Code Playgroud)

myMap.keySet()由此被称为只有一次.


Jam*_*s L 5

是的,无论哪种方式都只召唤一次