循环条件中方法调用的效率
我正在编写一个游戏引擎,其中使用for循环迭代在ArrayList
中保存的一组对象。 显然,效率是相当重要的,所以我想知道循环的效率。
for (String extension : assetLoader.getSupportedExtensions()) { // do stuff with the extension here }
其中getSupportedExtension()
返回String
的ArrayList
。 我想知道的是,每次循环遍历新扩展时是否调用该方法。 如果是这样,做以下事情会更有效率:
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
。
这两个片段将具有相同的性能。
- 直接成本。
因为,正如人们之前所言,以下
for (String extension : assetLoader.getSupportedExtensions()) { //stuff }
变成了
for (Iterator it = assetLoader.getSupportedExtensions().iterator(); it.hasNext();) { String extension = it.next(); //stuf }
getSupportedExtensions()被调用一次,你的两个代码片段都具有相同的性能成本,但不是通过List的最佳性能,因为……
- 间接开销
这是实例化和利用新的短生活对象的成本+方法的成本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选择器,用于将它们存储在集合中的原始装箱/取消装箱等。