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

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

问题描述

是否对Java中Collections的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++)
// ...

(好吧,让我们忘记大小是私有的.)编译器如何检查集合是否被修改?答案是,不需要这样做,因为大小已经在字段中可用,因此它要做的就是在每次迭代中访问size字段,但是访问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;
}

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

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.

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

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