Java foreach效率
我有这样的想法:Java foreach效率,java,performance,loops,foreach,premature-optimization,Java,Performance,Loops,Foreach,Premature Optimization,我有这样的想法: Map<String, String> myMap = ...; for(String key : myMap.keySet()) { System.out.println(key); System.out.println(myMap.get(key)); } 是的,无论哪种方式,它只被调用一次如果你想绝对确定,那么就用两种方式编译它,反编译并比较。我是通过以下来源完成的: public void test() { Map<String,
Map<String, String> myMap = ...;
for(String key : myMap.keySet()) {
System.out.println(key);
System.out.println(myMap.get(key));
}
是的,无论哪种方式,它只被调用一次如果你想绝对确定,那么就用两种方式编译它,反编译并比较。我是通过以下来源完成的:
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));
}
}
这就是你的答案。它以for循环形式调用一次。我相信它的编译器经过优化,每个循环条目只运行一次。
keySet()
只调用一次。“增强for循环”基于Iterable
接口,它使用该接口获得迭代器,然后用于循环。甚至不可能以任何其他方式迭代集合
,因为没有索引或任何可以获取单个元素的东西
然而,你真正应该做的是完全放弃这种微观优化的担忧——如果你曾经有过真正的性能问题,那么99%的可能性是你自己从来没有想过的事情。它只被调用一次。事实上,它使用一个迭代器来完成这个任务
此外,在你的情况下,我认为你应该使用
for (Map.Entry<String, String> entry : myMap.entrySet())
{
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
for(Map.Entry:myMap.entrySet())
{
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
避免每次在地图中搜索。答案在Java语言规范中,无需反编译:)这是我们可以阅读的内容:
增强的for语句具有
表格:
表达式必须具有以下两种类型之一
Iterable
否则它必须是
数组类型(§10.1)或编译时
发生错误
声明的局部变量的范围
在
增强的
声明(§14.14)是
所载声明
增强的对于
语句通过翻译成
用于语句的基本
如果表达式的类型是
Iterable
的子类型,然后让I
成为
表达式的类型
表达式。迭代器()
。增强的for
语句是等效的
对于
语句的基本
表格:
其中#i
是生成的编译器
不同于任何
其他标识符(编译器生成)
或其他)属于范围(§6.3)
在增强的
语句发生
否则,表达式必须
具有数组类型,T[]
。让L1。。。Lm
是的(可能为空)序列
紧跟在标签前面的标签
增强了
语句的。然后
增强型for语句的含义
由以下基本给出
声明:
T[] a = Expression;
L1: L2: ... Lm:
for (int i = 0; i < a.length; i++) {
VariableModifiersopt Type Identifier = a[i];
Statement
}
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()
只被调用一次。(增强的for循环的语法有点前后颠倒。)我不知道我是否同意调用这种过早的优化。想要了解编译器对代码所做的操作是合理的。我们也不知道他在项目的什么时候(如果他正在做一个项目,而不是在学术上提问)会问这个问题。可能就在最后,“你真正应该做的是完全放弃这种微优化担忧”他所担心的几乎不是一般的微优化…你可以构建一个恶意的特例,导致几乎任何东西的巨大性能问题,但这并没有改变这样一个事实:无论哪种方式,它几乎肯定都不会是一个问题——首先,我所见过的任何地图实现都会缓存密钥集。微观优化——我关心它!它们在复杂的程序中确实起到了作用@JavaTechnical:当然,它们起到了作用:它们使复杂的程序更难维护,甚至可能更慢。你一定要关心他们,避免他们。谢谢大家,分享你的智慧!我希望我的同龄人也一样!如果myMap.entrySet()不返回常量值(假设myMap在循环中更新,就像添加键值对一样),该怎么办?它只叫过一次吗?这不会产生奇怪的结果吗?@JavaTechnical:问题是,你不应该在更新时更改地图的内容,否则你会得到ConcurrentModificationException。如果需要在迭代时更改映射,唯一安全的方法是通过迭代器。哇!这很有趣。。。很好+1.很抱歉necro的评论,但这里有些奇怪。为什么println语句在for循环的结尾部分,而对next的调用在主体中?似乎是一个非常奇怪的设置。@Carcigenicate我同意,这是一个有趣的设置。但从逻辑上来说,它是成功的:当for循环的结束部分被执行时,迭代器上的next
方法已经被调用了,所以一切都非常棒。使用原始迭代器对我来说总是有点奇怪,因为在大多数情况下,实际的“迭代”显式地发生在循环的开始,而我习惯于在上一个循环的结束时发生(至少在概念上)。
EnhancedForStatement:
for ( VariableModifiersopt Type Identifier: Expression) Statement
for (I #i = Expression.iterator(); #i.hasNext(); ) {
VariableModifiersopt Type Identifier = #i.next();
Statement
}
T[] a = Expression;
L1: L2: ... Lm:
for (int i = 0; i < a.length; i++) {
VariableModifiersopt Type Identifier = a[i];
Statement
}
for (Iterator<String> iterator = myMap.keySet().iterator(); iterator.hasNext();) {
String key = iterator.next();
System.out.println(key);
System.out.println(myMap.get(key));
}