Java foreach效率

我有这样的事情:

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

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

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

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

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

 public void test() { Map myMap = new HashMap(); for (String key : myMap.keySet()) { System.out.println(key); System.out.println(myMap.get(key)); } Set 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-loopforms调用一次。

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

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

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

避免每次在地图中搜索。

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

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

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

增强的for语句具有以下forms:

 EnhancedForStatement: for ( VariableModifiersopt Type Identifier: Expression) Statement 

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

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

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

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

 for (I #i = Expression.iterator(); #i.hasNext(); ) { VariableModifiersopt Type Identifier = #i.next(); Statement } 

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

否则,Expression必须具有数组类型T[] 。 设L1 ... Lm是紧接在增强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 (Iterator iterator = myMap.keySet().iterator(); iterator.hasNext();) { String key = iterator.next(); System.out.println(key); System.out.println(myMap.get(key)); } 

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

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

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