7

I just started learning Java and the first thing I came across is the foreach loop, not knowing the way it works the first thing I did was:

int[] array = new int [10];
for (int i: array){
    i = 1;
}

And obviously failed to assign 1 to every element of the array. Then I added System.out.print(i); (after i = 1;) to the body of the loop and saw that the output of the screen was 1111111111 but since doing something with i inside the loop is valid that most likely i is a copy of every element of the array, ain't it? (first questions)

If the above is true doesn't this mean that the foreach loop is much slower then the common for loop since it involves making copies of each element of the array? Or since Java doesn't have pointers and pointer arithmetic, the oprator[] may be designed in some other "badly" fashion that copying every element is actually faster?

And if the above assumptions are true, why one would use an obviously slower foreach loop instead of a common forloop?

In short the questions:

  • Is i the copy of each element of the array? If not what is it then?

  • Isn't the foreach loop slower then the common one? If not, how "badly" is then operator[] designed?

  • There is nothing more except readability to win in a foreach loop?

Alexandru Barbarosie
  • 2,952
  • 3
  • 24
  • 46

4 Answers4

11

In the code

for (int i: array){

You declare a variable i that on each loop iteration gets the value of the next element in the array, it isn't a reference to that element.

In

i = 1;

you assign a new value to the variable, not to the element in the array.

You cannot set the values of array elements with a foreach loop directly. Use a normal for loop for that

for (int i = 0; i < array.length; i++) {
    array[i] = ...; // some value
}

In the above example, you are using the declared variable i as an index to the element in the array.

array[i] 

is accessing the element itself whose value you can modify.


Ans obviously failed to assign 1 to every element of the array. The I added System.out.print(i); to the body of the loop and saw that the output of the screen was 1111111111 but since doing something with i inside the loop is valid that most likely i is a copy of every element of the array, ain't it? (first questions)

You must have put the System.out.print(i) after the i = 1, otherwise you would get 0000000.

If the above is true doesn't this mean that the foreach loop is much slower then the common for loop since it involves making copies of each element of the array? Or since Java doesn't have pointers and pointer arithmetic, the oprator[] may be designed in some other "badly" fashion that copying every element is actually faster?

Have a look here to see how the foreach loop works. For arrays,

for (int i: array){
    i = 1;
}

is equivalent to

for (int index = 0; index < array.length; index++) {
    int i = array[index];
    i = 1;
}

So it isn't slower. You're doing one more primitive creation on the stack.

It depends on the implementation. For arrays, it's not slower in any way. It just serves different purposes.

why one would use an obviously slower foreach loop instead of a common forloop?

One reason is for readability. Another is when you don't care about changing the element references of the array, but using the current references.

Take a reference type example

public class Foo {
    public int a;
}

Foo[] array = new Foo[3];
for (int i = 0; i < array.length; i++) {
    array[i] = new Foo();
    array[i].a = i * 17;
}

for (Foo foo : array) {
    foo.a = 0; // sets the value of `a` in each Foo object
    foo = new Foo(); // create new Foo object, but doesn't replace the one in the array
}

With primitive types such a thing doesn't work.

for (int index = 0; index < array.length; index++) { 
    int i = array[index];
    i = 1; // doesn't change array[index]
}
Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • I know that. This is not my question. – Alexandru Barbarosie Sep 13 '13 at 14:05
  • 1
    @AlexandruBarbarosie Take a look for the actual answers. – Sotirios Delimanolis Sep 13 '13 at 14:09
  • 1
    @AlexandruBarbarosie I've highlighted my answers. – Sotirios Delimanolis Sep 13 '13 at 14:21
  • 1
    So `i` is a copy of every element of the array? Looking through the Q&A you gave the link and assuming `i.next();` is called in the background of each `foreach` loop, it does make it slower. You also say "it's not slower in any way" so then: is it faster? Then how badly is [] designed that making copies is faster the accessing elements using [] operator? There is nothing more except readability to win in a foreach loop? – Alexandru Barbarosie Sep 13 '13 at 14:27
  • @AlexandruBarbarosie `i` holds a copy of the value of each element in the array. Changing `i` won't change the element. I've updated my answer with the equivalent transformation. Use a foreach loop if you only want to use the values of the array, but not change them. – Sotirios Delimanolis Sep 13 '13 at 14:31
  • +1 nice answer.. `for each` is more readable, i `performance` is meaningless between `for` and `foreach` – nachokk Sep 13 '13 at 14:33
  • @SotiriosDelimanolis That's not entirely true, you can 'change' the values, problem here is, that he loops over primitive types. One can't change the reference, but one can as always invoke methods on objects that change their inner state (as long as they are not immutable). – mike Sep 13 '13 at 14:41
  • I see your equivalence. But it is in terms of code and since you also said that `i` is a copy obviously the two lops will result in two different bytecodes. I'm looking for a deeper answer trying to understand what happens if the back ground. – Alexandru Barbarosie Sep 13 '13 at 14:42
  • @AlexandruBarbarosie You can always compile and look at the bytecode with `javap`. They will produce different bytecodes because the `foreach` will have a new variable created. That's minimal effect to performance and you really shouldn't care about it. – Sotirios Delimanolis Sep 13 '13 at 14:43
  • @AlexandruBarbarosie Take a look at my answer. Mostly the iterator is called. I can't tell what is done in case of arrays, I'm no sure whether they implement `Iterable`. – mike Sep 13 '13 at 14:44
  • @AlexandruBarbarosie I think the critical point you're missing is that `i` is holding a primitive type here. It's not a **copy**; it's just another reference to that value. `i = 1` doesn't change the value because you can't **change** a primitive; you just point to something else instead. If you had an array of some other object, you could alter those objects. – Henry Keiter Sep 13 '13 at 14:45
  • @HenryKeiter true, I totally forgot about that. So changing the state of an object is possible inside the `foreach` loop? Does that mean that generally speaking it is some kind of "special" reference? – Alexandru Barbarosie Sep 13 '13 at 14:52
  • @AlexandruBarbarosie I've added a small example with reference types that might help. – Sotirios Delimanolis Sep 13 '13 at 14:53
  • @SotiriosDelimanolis I see, thank you for trying to clarify, it is almost the answer I needed, but I will still w8 some time, mb I'll get something more. Still want to understand what happens in the back ground. – Alexandru Barbarosie Sep 13 '13 at 15:00
  • @AlexandruBarbarosie You're welcome. What's missing from your understanding? I can post some bytecode. – Sotirios Delimanolis Sep 13 '13 at 15:01
  • @SotiriosDelimanolis that might work because I still don't understand what that `i` actually is. – Alexandru Barbarosie Sep 13 '13 at 15:03
  • lol, AlexandruBarbarosie and @HenryKeiter I previously mentioned that is possible to change the state :D But two are better than one! :) – mike Sep 13 '13 at 15:18
  • @AlexandruBarbarosie I went through the byte code and it won't help. What you need to understand, I think, is that in `int i = array[0]`, the variable `i` holds a copy of the value at index `0` of the `array`. The only way to modify the value of the array element is to do `array[0] = 42;`. – Sotirios Delimanolis Sep 13 '13 at 15:19
7

From Item 46 in Effective Java by Joshua Bloch :

The for-each loop, introduced in release 1.5, gets rid of the clutter and the opportunity for error by hiding the iterator or index variable completely. The resulting idiom applies equally to collections and arrays:

// The preferred idiom for iterating over collections and arrays
for (Element e : elements) {
    doSomething(e);
}

When you see the colon (:), read it as “in.” Thus, the loop above reads as “for each element e in elements.” Note that there is no performance penalty for using the for-each loop, even for arrays. In fact, it may offer a slight performance advantage over an ordinary for loop in some circumstances, as it computes the limit of the array index only once. While you can do this by hand (Item 45), programmers don’t always do so.

Advantages

  1. Readability
  2. It increases the abstraction level - instead of having to express the low-level details of how to loop around a list or array (with an index or iterator), the developer simply states that they want to loop and the language takes care of the rest.

Disadvantage:

Cannot access the index or to remove an item.

To sum up,

the enhanced for loop offers

  1. A concise higher level syntax to loop over a list or array which

    1.1 improves clarity

    1.2 readability.

    However, it misses : allowing to access the index loop or to remove an item.

JNL
  • 4,683
  • 18
  • 29
3

Setting the values by reference didn't work because int is a primitive type. For any kind of Object[] it would work. Making a copy of a primitive type is very fast, and will be done by the processor many times without your realising.

The foreach loop is more readable, but it's also more writeable. A common programmer error is:

for (int i = 0; i < 10; i++)
{
    for(int j = 0; j < 10; i++) //oops, incrementing wrong variable!
    {
        //this will not execute as expected
    }
}

It's impossible to make this error using a foreach loop.

MikeFHay
  • 8,562
  • 4
  • 31
  • 52
2

The for statement also has another form designed for iteration through Collections and arrays This form is sometimes referred to as the enhanced for statement, and can be used to make your loops more compact and easy to read. http://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html

So, you're right. Readability is the main win here. For further information on the for each loop, or enhanced for loop, here a blog entry from oralce.

The for each utilized the functionality of the Iterable<E> interface, so the performance depends on the implementation.

mike
  • 4,929
  • 4
  • 40
  • 80