5

I'm just curious: Is there a difference on speed and performance between this two loops implementation? Assume that size() method returns the length of the array,collection, or object that handles a group of elements (actually it's from XOM api).

Implementation 1:

int size = someArray.size();
for (int i = 0; i < size; i++) {
    // do stuff here
}

Implementation 2:

for (int i = 0; i < someArray.size(); i++) {
    // do stuff here
}
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
John Bautista
  • 1,480
  • 3
  • 29
  • 60

6 Answers6

4

From a performance point of view, there is little difference. This is because a loop can be optimized so that the size() lookup is inlined, resulting in very little performance difference.

The main difference is if the size changes while looping. The first case will try to iterate a fixed number of times. In the second case, the number of iterations will depend on the final size().

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

The 1st snippet is bound to execute faster since it calls size() once only. The 2nd snippet calls size() N times. Depending on the impl. it might pose significant penalty, esp. if the compiler finds hard to inline the method and/or the size() method doesn't just return non-volatile variable, etc.

I'd have rewritten it like for(int i=0, s=someCollection.size(); i<s; i++)

Note: arrays don't have size() method.

bestsss
  • 11,796
  • 3
  • 53
  • 63
  • @bestss that's why I specified it in general (for groups of elements) :) – John Bautista Feb 26 '11 at 10:31
  • @Jairo, there is Huge difference between arrays and collections. arrays cannot change their size under any circumstances. `for(int i=0;i – bestsss Feb 26 '11 at 10:38
  • @bestsss: surely an ArrayList does have a *size()* method and is, somehow, an array ;) – SyntaxT3rr0r Feb 26 '11 at 10:41
  • @SyntaxT3rr0r, an ArrayList is not an array. It's a wrapper, and it can change its size (not like an array) by allocating a new array. That's why you can't always optimize away the size() call for an ArrayList, while for true arrays it's trivial. – Sergei Tachenov Feb 26 '11 at 10:46
  • @Sergey Tachenov: I've got 5K+ rep only on Java questions, I know what a Java array is, thanks ;) My point what that if some god at Sun decided to name that "thing" ArrayList well... it means that, somehow, it must be related to an "array" (now you can keep arguing: but either it's somehow an array and I'm right **or** the Sun gods where wrong and stupid when they decided to name that collection *ArrayList*... I think you won't like it either way ;) – SyntaxT3rr0r Feb 26 '11 at 10:52
  • @SyntaxT3rr0r, "related to array" and "is an array" are obviously different things. If it was an array, it would probably be named ListArray or something. You aren't going to say that CharSequence is a char? But terminology is really irrelevant here. What's relevant is the difference between regularArray.length and arrayList.size(). – Sergei Tachenov Feb 26 '11 at 11:04
  • @Sergey Tachenov: but surely I **NEVER** wrote "is an array". I wrote "is, **somehow**, an array". And, of course, laking any intellectual honesty and any sense of humor you choosed to ignore that... Somehow ;) Now you can have the last word, I'm not responding to you anymore... Somehow ;) – SyntaxT3rr0r Feb 26 '11 at 11:09
  • @Sergey Tachenov, the reference (to array) is a glaring sarcasm, no need for such daft offenses here. – bestsss Feb 26 '11 at 11:14
  • @bestsss, I understand now... somehow. My English just isn't good enough to detect sarcasm promptly. Never indented to offend anyone, though. – Sergei Tachenov Feb 26 '11 at 11:21
  • @Sergey, yeah, my native language is written in cyrillic as well :) but the smile " ;) " at the end is a good pointer. – bestsss Feb 26 '11 at 11:24
1

Yes, there is a difference. In the first loop, the size() method is only called once. In the second one, it's called at each iteration.

If the iteration modifies the size of the collection (which is very very uncommon), the second one is needed. In most cases, you should prefer the first one, but limit the scope of the size variable :

for (int i = 0, size = someArray.size(); i < size; i++) {
    // ...
}

But most of the time, you should prefer the foreach syntax anyway :

for (Foo foo : collection) {
    // ...
}

which will iterate over the array or collection efficiently, even for a LinkedList for example, where indexed access is not optimal.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • I think I cannot use **foreach** in my case. The XOM API's Elements feature cannot be traversed that way. (XOM is an XML-processing library for Java) – John Bautista Feb 26 '11 at 10:35
  • 1
    if the size can vary during the iteration then there's probably a verious serious design/synchronization issue. Moreover in such a loop it's highly probable that there will be a *get(i)* and if the size change, it can change, for example, *after* re-reading the size but *before* doing the get, in which case the code shall throw an exception. – SyntaxT3rr0r Feb 26 '11 at 10:39
  • @SyntaxT3rr0r: agreed. I was thinking about a loop which adds/removes items from the collection inside the iteration (no multithreading). But I agree it's very very uncommon. I'll edit my answer to be clearer. – JB Nizet Feb 26 '11 at 10:44
  • if you add/remove during the loop, make well sure you change size variable accordingly. Simple solution is `size=collection.size()`, other include size++ or size-- and so on. – bestsss Feb 26 '11 at 11:29
1

Don't worry about it, JVM optimization is very aggressive these days.

Use the 2nd form, for it's more readable, and most likely as fast. Premature optimization yada yada.

And when you do need to improve speed, always profile first, don't guess.

It is extremely unlikely that caching size() in a local variable could benefit your app noticeably. If it does, you must be doing simple operations over a huge dataset. You shouldn't use ArrayList at all in that case.

irreputable
  • 44,725
  • 9
  • 65
  • 93
0

Always avoid anything that can be done outside of the loop like method calls, assigning values to variables, or testing for conditions.

Method calls are more costly than the equivalent code without the call, and by repeating method calls again and again, you just add overhead to your application.

Move any method calls out of the loop, even if this requires rewriting of the code.

Benefits :-

Unless the compiler optimizes it, the loop condition will be calculated for each iteration over the loop.

If the condition value is not going to change, the code will execute faster if the method call is moved out of the loop.

Note :-

If the method returns a value that will not change during the loop, then store its value in a temporary variable before the loop.

Hence its value is stored in a temporary variable size outside the loop, and then used as the loop termination condition.

Nikhil Kumar
  • 2,618
  • 3
  • 21
  • 24
0

Maybe it is worth to note that this construct:

for (String s : getStringsList()) {
    //...
}

invokes getStringsList() only once and then operates on iterator behind the scenes. So it is safe to perform lengthy operations or change some state inside getStringsList().

Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • *So it is safe to perform lengthy operations or change some state inside getStringsList().* most likely if that happens a ConcurrentModificationException is on the line (erm stack) – bestsss Feb 26 '11 at 21:20
  • I don't quite understand. What I meant is that `getStringsList()` might be an expensive method (e.g. from DAO) because it is called only once, before the loop starts. After that the for loop operates on returned list, or - to be more precise - on the iterator. Where is the place for `ConcurrentModificationException`? I assume getStringsList() does not hold the reference to returned list. – Tomasz Nurkiewicz Feb 26 '11 at 21:40