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