for循环条件中方法调用的效率

Efficiency of method call in for loop condition

我正在编写一个游戏引擎,其中 ArrayList 中的一组对象使用 for 循环进行迭代。显然,效率很重要,所以我想知道循环的效率。

for (String extension : assetLoader.getSupportedExtensions()) {
    // do stuff with the extension here
}

其中 getSupportedExtension() returns ArrayListString。我想知道的是,每次循环迭代新扩展时是否调用该方法。如果是这样,做这样的事情会更有效率吗:

ArrayList<String> supportedExtensions = ((IAssetLoader<?>) loader).getSupportedExtensions();

for (String extension : supportedExtensions) {
    // stuff
}

?提前致谢。

不,方法 assetLoader.getSupportedExtensions() 在循环的第一次迭代之前只被调用一次,用于创建增强的 for 循环使用的 Iterator<String>

这两个片段将具有相同的性能。

根据规范,成语

for (String extension : assetLoader.getSupportedExtensions()) {
  ...
}

扩展为

for (Iterator<String> it = assetLoader.getSupportedExtensions().iterator(); it.hasNext();)
{
    String extension = it.next();
    ...
}

因此,您询问的调用只发生一次,在循环初始化时。它是迭代器对象,其方法被重复调用。

但是,如果您真的对应用程序的性能感兴趣,那么您应该确保您关注的是大赢家,而不是像这样的小人物。几乎不可能使 getter 调用成为任何代码段中的瓶颈。这对于 HotSpot 上的应用程序 运行 来说是双倍的,它将内联 getter 调用并将其转换为直接字段访问。

  1. 直接成本。

因为,正如人们之前所说,以下

for (String extension : assetLoader.getSupportedExtensions()) {
  //stuff
}

变身

for (Iterator<String> it = assetLoader.getSupportedExtensions().iterator(); it.hasNext();) {
    String extension = it.next();
    //stuf
}

getSupportedExtensions() 被调用一次,您的两个代码片段具有相同的性能成本,但不是通过列表的最佳性能,因为...

  1. 间接成本

这是实例化和使用新的短期对象的成本 + 方法 next() 的成本。方法 iterator() 准备 Iterator 的实例。因此,需要花时间实例化对象,然后(当该对象变得不可访问时)对其进行 GC。总的间接成本不是 so 很多(大约 10 条指令为新对象分配内存 + 一些构造函数指令 + 大约 5 行 ArrayList.Itr.next() + 删除来自 Eden 的次要 GC 上的对象),但我个人更喜欢索引(甚至是普通数组):

ArrayList<String> supportedExtensions = ((IAssetLoader<?>) loader).getSupportedExtensions();

for (int i = 0; i < supportedExtensions.size(); i++) {
    String extension = supportedExtensions.get(i);
    // stuff
}

当我必须在我的应用程序的主路径中频繁地遍历列表时,过度迭代。具有隐藏成本的标准 java 代码的其他一些示例是一些字符串方法(substring()、trim() 等)、NIO 选择器、将它们存储在集合中的原语 boxing/unboxing 等.