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

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

问题描述

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.....


$ b b

每个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++)
// ...


$ b b

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

当集合被修改时会发生什么,

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天全站免登陆