22

我有这样的事情:

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

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

所以在foreach 循环myMap.keySet()中被调用一次?我认为是,但想听听你的意见。

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

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

6 回答 6

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 循环形式调用一次。

于 2009-05-24T20:34:17.107 回答
35

它只被调用一次。事实上,它使用了一个迭代器来解决这个问题。

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

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

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

于 2009-05-24T20:57:19.757 回答
9

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

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

于 2009-05-24T20:38:25.303 回答
7

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

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

EnhancedForStatement:
        for ( VariableModifiersopt Type Identifier: Expression) Statement

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

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

增强语句的含义for 通过翻译成基本for语句来给出。

如果 的 类型Expression是 的子类型Iterable,则令I为表达式 Expression 的类型。iterator(). 增强for语句等价于for以下形式的基本语句:

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

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

where#i是一个编译器生成的标识符,它与增强 for 语句发生时范围内(第 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
}

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

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

于 2010-01-14T03:39:00.727 回答
5

是的,无论哪种方式都只调用一次

于 2009-05-24T20:33:05.783 回答
-3

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

于 2009-05-24T20:35:03.453 回答