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 }
其中a和i是编译器生成的标识符,这些标识符与发生增强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()
只被调用一次。
是的,无论哪种方式都只召唤一次
我相信它的编译器经过优化,每个循环条目只运行一次。