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

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

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

其中getSupportedExtension()返回StringArrayList 。 我想知道的是,每次循环遍历新扩展时是否调用该方法。 如果是这样,做以下事情会更有效率:

 ArrayList supportedExtensions = ((IAssetLoader) loader).getSupportedExtensions(); for (String extension : supportedExtensions) { // stuff } 

? 提前致谢。

通过规范,成语

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

扩展到

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

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

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

不,方法assetLoader.getSupportedExtensions()仅在循环的第一次迭代之前调用一次,并用于创建增强型for循环使用的Iterator

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

  1. 直接成本。

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

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

变成了

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

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

  1. 间接开销

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

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

当我不得不在我的应用程序的主路径中经常遍历列表时,重复迭代。 隐藏成本的标准java代码的一些其他示例是一些String方法(substring(),trim()等),NIO选择器,用于将它们存储在集合中的原始装箱/取消装箱等。