简体   繁体   中英

Performance loss of continued call to array.length or list.size()

I have seen people say to cache the values of size for a list or length for an array when iterating, to save the time of checking the length/size over and over again.

So

for (int i = 0; i < someArr.length; i++) // do stuff
for (int i = 0; i < someList.size(); i++) // do stuff

Would be turned into

for (int i = 0, length = someArr.length; i < length; i++) // do stuff
for (int i = 0, size = someList.size(); i < size; i++) // do stuff

But since Array#length isn't a method, just a field, shouldn't it not have any difference? And if using an ArrayList, size() is just a getter so shouldn't that also be the same either way?

It is possible the JIT compiler will do some of those optimizations for itself. Hence, doing the optimizations by hand may be a complete waste of time.

It is also possible (indeed likely) that the performance benefit you are going to get from hand optimizing those loops is too small to be worth the effort. Think of it this way:

  • Most of the statements in a typical program are only executed rarely
  • Most loops will execute in a few microseconds or less .
  • Hand optimizing a program takes in the order of minutes or hours of developer time.
  • If you spend minutes to get a execution speedup that is measured in microseconds, you are wasting your time. Even thinking about it too long is wasting time.

The corollary is that:

  • You should benchmark your code to decide whether you need to optimize it.
  • You should profile your code to figure out which parts of your code is worth spending optimization effort on.
  • You should set (realistic) performance goals, and stop optimization when you reach those goals.

Having said all of that:

  • theArr.length is very fast, probably just a couple of machine instructions
  • theList.size() will probably also be very fast, though it depends on what List class you are using.
  • For an ArrayList the size() call is probably a method call + a field fetch versus a field fetch for length .
  • For an ArrayList the size() call is likely to be inlined by the JIT compiler... assuming that the JIT compiler can figure that out.
  • The JIT compiler should be able to hoist the length fetch out of the loop. It can probably deduce that it doesn't change in the loop.
  • The JIT compiler might be able to hoist the size() call, but it will be harder for it to deduce that the size doesn't change.

What this means is that if you do hand optimize those two examples, you will most likely get negligible performance benefit.

In general the loss is negligible. Even a LinkedList.size() will use a stored count, and not iterate over all nodes.

For large sizes you may assume the conversion to machine code may catch up, and optimize it oneself.

If inside the loop the size is changed (delete/insert) the size variable must be changed too, which gives us even less solid code.

The best would be to use a for-each

for (Bar bar: bars) { ... }

You might also use the somewhat more costing Stream:

barList.forEach(bar -> ...);
Stream.of(barArray).forEach(bar -> ...);

Streams can be executed in parallel.

barList.parallelStream().forEach(bar -> ...);

And last but not least you may use standard java code for simple loops:

Arrays.setAll(barArray, i -> ...);

We are talking here about micro-optimisations . I would go for elegance.

Most often the problem is the used algorithm & datastructurs. List is notorious, as everything can be a List . However Set or Map often provide much higher power/expressiveness.

If a complex piece of software is slow, profile the application. Check the break lines: java collections versus database queries, file parsing.

It is best not to call a method on every loop round, so you should avoid calling size() on the condition part that is evaluated on every round. If you use a for each loop, this does not apply.

for (int i = 0; i < foos.bar(); i++) // slow

for (int i = 0, size = foos.bar(); i < size; i++) // fast

for (Foo foo : foo.bar()) // fast

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM