我有这样的事情:
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) {
...
}
答案 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
的类型是aIterable
的子类型,然后让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)
我相信它的编译器经过优化,每个循环条目只运行一次。