flypen
flypen

Reputation: 2585

Is the loop condition calculated each loop for "for" sentence in Java?

This is my Java code:

List<Object> objects = new ArrayList();

// Assign values to objects
...

for (int i = 0; i < objects.size(); i++) {
    Object object = objects.get(i);
    ...
}

I have two questions:

  1. Is objects.size() calculated only once before stating the loop, or is it calculated each loop?
  2. If objects.size() is calculated each loop, then if other thread change it at the same time without multi-threads protection, the code may be crashed.

Am I correct?

Upvotes: 14

Views: 8111

Answers (6)

Bohemian
Bohemian

Reputation: 425053

Answers:

  1. objects.size() is called every loop (whether it is calculated depends on the ArrayList implementation, which you shouldn't care about)
  2. Yes, another thread may change the list and this will affect your loop

Real answer:

You shouldn't have to care, and here's how you don't have to:

  1. Use a CopyOnWriteArrayList, which is thread-safe. If you iterate over it using an Iterator (as the foreach syntax uses internally), you'll iterate over the list as it was when the iteration started
  2. Use the foreach syntax, which means you don't have to use an index etc - it's done for you:

for (Object object : objects) {
    // do something with each object 
}

Upvotes: 16

Peter Lawrey
Peter Lawrey

Reputation: 533530

Notionally the objects.size() could be evaluated on each loop. However, as the method is short it can be inlined and cached as its not a volatile variable. i.e. another thread could change it but there is no guarantee that if it did you would see the change.

A short way to save the size is to use the follow.

for (int i = 0, size = objects.size(); i < size; i++) {
    Object object = objects.get(i);
...
}

However if you are concerned that another thread could change the size, this approach only protects you if an object is added. If an object is removed you can still get an exception when you attempt to access the value which is now beyond the end of the list.

Using a CopyOnWriteArrayList avoids these issues (provided you use an Iterator) but makes writes more expensive.

Upvotes: 1

Karl Knechtel
Karl Knechtel

Reputation: 61526

  1. Is objects.size() calculated only once before stating the loop, or is it calculated each loop?

Each time.

  1. If objects.size() is calculated each loop, then if other thread change it at the same time without multi-threads protection, the code may be crashed.

Yes. Or at least, you may get a ConcurrentModificationException, and not have any reasonable way to deal with it.

Please note that this could happen even if you cached objects.size(), except now the .get() will fail instead because you are trying to get an index that no longer exists. objects.size() changes because something is removed from, or added to, the container.

Don't modify collections while you are iterating over them.

Upvotes: 1

Hemant Metalia
Hemant Metalia

Reputation: 30648

yes when you are using objects.size() inside the loop condition it calculates every time. better way is to keep it in a variable before going into loop; like int

 limit=objects.size(); 
 for (int i = 0; i < limit; i++) {
    Object object = objects.get(i);
 ...
 }

If you have another thread it may change it but using the above option it will not affect or crash you programm.

Upvotes: 2

Ashish
Ashish

Reputation: 1567

yes , it will calculate each time

if you look into for loop statement, in the first statement it will set counter initial value then it will check for maximum value then it will execute for loop body then after it will increase value of counter and then again check for maximum value. every time to check maximum value it will call size method.

Upvotes: 1

Todd
Todd

Reputation: 31710

Yes, it is calculated each time. If you have another thread altering the size of your objects list, the loop condition will keep changing.

Upvotes: 9

Related Questions