在 for 循环比较中使用集合大小 [英] Using collection size in for loop comparison

查看:23
本文介绍了在 for 循环比较中使用集合大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Java 中集合的 size() 方法是否有编译器优化?

Is there a compiler optimization for the size() methods of Collections in Java?

考虑以下代码:

for(int i=0;i<list.size();i++)
      ...some operation.....

每个 i 都会调用 size() 方法.找出尺寸并重新使用它不是更好吗?(方法调用有开销).

There is a call to the size() methods for every i. Won't it be better to find out the size and reuse it? (Method calls have overheads).

final int len = list.size()
for(int i=0;i<len;i++)
      ...some operation.....

然而,当我对这两个代码片段计时时,没有显着的时间差异,即使我高达 10000000.我在这里遗漏了什么吗?

However, when I timed both these code pieces there was no significant time difference, even for i as high as 10000000. Am I missing something here?

Update1:​​ 我知道除非集合发生变化,否则不会再次计算大小.但是必须有一些与方法调用相关的开销.编译器是否总是内联这些(请参阅 Esko 的回答)?

Update1: I understand that the size is not computed again unless the collection changes. But there has to be some overhead associated with a method call. Is it the case that the compiler always inlines these (See Esko's answer)?

更新 2:我的好奇心被进一步激发了.从给出的答案中,我看到好的 JIT 编译器通常会内联这个函数调用.但是他们仍然必须确定集合是否被修改.我不接受答案,希望有人能就编译器如何处理这一问题给我指点.

Update 2: My curiosity has been fueled further. From the answers given, I see that good JIT compilers will often inline this function call. But they will still have to determine whether the collection was modified or not. I am not accepting an answer in the hope that someone will give me pointers regarding how this is handled by compilers.

推荐答案

好的,这是 JDK 源代码的摘录(JDK 文件夹中的 src.zip):

Okay, here is an excerpt from the JDK sources (src.zip in the JDK folder):

public int size() {
    return size;
}

这是来自 ArrayList,但我认为其他集合也有类似的实现.现在,如果我们想象编译器内联 size() 调用(这很有意义),您的循环就会变成这样:

This is from ArrayList, but I think other collections have similar implementations. Now if we imagine that the compiler inlines the size() call (which would make perfect sense), your loop turns into this:

for(int i=0;i<list.size;i++)
// ...

(好吧,让我们忘记大小是私有的.)编译器如何检查集合是否被修改?答案是它不需要也不需要这样做,因为大小已经在字段中可用,所以它所要做的就是在每次迭代时访问大小字段,但是访问 int 变量非常快手术.请注意,它可能会计算一次其地址,因此它甚至不必在每次迭代时取消引用列表.

(Well, let's forget that the size is private.) How does compiler checks if the collection was modified? The answer that it doesn't and doesn't need to do so because the size is already available in the field, so all it has to do is to access the size field on each iteration, but accessing an int variable is a very fast operation. Note that it probably calculates its address once, so it doesn't even have to dereference list on each iteration.

例如通过 add() 方法修改集合时会发生什么?

What happens when the collection is modified, say, by the add() method?

public boolean add(E e) {
    ensureCapacity(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

如您所见,它只是增加了大小字段.所以编译器实际上不需要做任何事情来确保它可以访问最新的大小.唯一的例外是,如果您从另一个需要同步的线程修改集合,否则循环线程可能会看到其本地缓存的大小值,该值可能会也可能不会更新.

As you can see, it just increases the size field. So the compiler doesn't actually need to do anything to ensure it has access to the latest size. The only exception would be that if you modify the collection from another thread you need to synchronize, otherwise the loop thread may see its local cached value of size which may or may not be updated.

这篇关于在 for 循环比较中使用集合大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆