[java] How does the enhanced for statement work for arrays, and how to get an iterator for an array?

Given the following code snippet:

int[] arr = {1, 2, 3};
for (int i : arr)
    System.out.println(i);

I have the following questions:

  1. How does the above for-each loop work?
  2. How do I get an iterator for an array in Java?
  3. Is the array converted to a list to get the iterator?

This question is related to java arrays iterator foreach

The answer is


I like the answer from 30thh using Iterators from Guava. However, from some frameworks I get null instead of an empty array, and Iterators.forArray(array) does not handle that well. So I came up with this helper method, which you can call with Iterator<String> it = emptyIfNull(array);

public static <F> UnmodifiableIterator<F> emptyIfNull(F[] array) {
    if (array != null) {
        return Iterators.forArray(array);
    }
    return new UnmodifiableIterator<F>() {
        public boolean hasNext() {
            return false;
        }

        public F next() {
            return null;
        }
    };
}

In Java 8:

Arrays.stream(arr).iterator();

For (2), Guava provides exactly what you want as Int.asList(). There is an equivalent for each primitive type in the associated class, e.g., Booleans for boolean, etc.

    int[] arr={1,2,3};
    for(Integer i : Ints.asList(arr)) {
      System.out.println(i);
    }

Arrays.asList(arr).iterator();

Or write your own, implementing ListIterator interface..


You can't directly get an iterator for an array.

But you can use a List, backed by your array, and get an ierator on this list. For that, your array must be an Integer array (instead of an int array):

Integer[] arr={1,2,3};
List<Integer> arrAsList = Arrays.asList(arr);
Iterator<Integer> iter = arrAsList.iterator();

Note: it is only theory. You can get an iterator like this, but I discourage you to do so. Performances are not good compared to a direct iteration on the array with the "extended for syntax".

Note 2: a list construct with this method doesn't support all methods (since the list is backed by the array which have a fixed size). For example, "remove" method of your iterator will result in an exception.


public class ArrayIterator<T> implements Iterator<T> {
  private T array[];
  private int pos = 0;

  public ArrayIterator(T anArray[]) {
    array = anArray;
  }

  public boolean hasNext() {
    return pos < array.length;
  }

  public T next() throws NoSuchElementException {
    if (hasNext())
      return array[pos++];
    else
      throw new NoSuchElementException();
  }

  public void remove() {
    throw new UnsupportedOperationException();
  }
}

Google Guava Libraries collection provides such function:

Iterator<String> it = Iterators.forArray(array);

One should prefere Guava over the Apache Collection (which seems to be abandoned).


I'm a bit late to the game, but I noticed some key points that were left out, particularly regarding Java 8 and the efficiency of Arrays.asList.

1. How does the for-each loop work?

As Ciro Santilli ???? ??? ??? pointed out, there's a handy utility for examining bytecode that ships with the JDK: javap. Using that, we can determine that the following two code snippets produce identical bytecode as of Java 8u74:

For-each loop:

int[] arr = {1, 2, 3};
for (int n : arr) {
    System.out.println(n);
}

For loop:

int[] arr = {1, 2, 3};

{  // These extra braces are to limit scope; they do not affect the bytecode
    int[] iter = arr;
    int length = iter.length;
    for (int i = 0; i < length; i++) {
        int n = iter[i];
        System.out.println(n);
    }
}

2. How do I get an iterator for an array in Java?

While this doesn't work for primitives, it should be noted that converting an array to a List with Arrays.asList does not impact performance in any significant way. The impact on both memory and performance is nearly immeasurable.

Arrays.asList does not use a normal List implementation that is readily accessible as a class. It uses java.util.Arrays.ArrayList, which is not the same as java.util.ArrayList. It is a very thin wrapper around an array and cannot be resized. Looking at the source code for java.util.Arrays.ArrayList, we can see that it's designed to be functionally equivalent to an array. There is almost no overhead. Note that I have omitted all but the most relevant code and added my own comments.

public class Arrays {
    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

    private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable {
        private final E[] a;

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }

        @Override
        public int size() {
            return a.length;
        }

        @Override
        public E get(int index) {
            return a[index];
        }

        @Override
        public E set(int index, E element) {
            E oldValue = a[index];
            a[index] = element;
            return oldValue;
        }
    }
}

The iterator is at java.util.AbstractList.Itr. As far as iterators go, it's very simple; it just calls get() until size() is reached, much like a manual for loop would do. It's the simplest and usually most efficient implementation of an Iterator for an array.

Again, Arrays.asList does not create a java.util.ArrayList. It's much more lightweight and suitable for obtaining an iterator with negligible overhead.

Primitive arrays

As others have noted, Arrays.asList can't be used on primitive arrays. Java 8 introduces several new technologies for dealing with collections of data, several of which could be used to extract simple and relatively efficient iterators from arrays. Note that if you use generics, you're always going to have the boxing-unboxing problem: you'll need to convert from int to Integer and then back to int. While boxing/unboxing is usually negligible, it does have an O(1) performance impact in this case and could lead to problems with very large arrays or on computers with very limited resources (i.e., SoC).

My personal favorite for any sort of array casting/boxing operation in Java 8 is the new stream API. For example:

int[] arr = {1, 2, 3};
Iterator<Integer> iterator = Arrays.stream(arr).mapToObj(Integer::valueOf).iterator();

The streams API also offers constructs for avoiding the boxing issue in the first place, but this requires abandoning iterators in favor of streams. There are dedicated stream types for int, long, and double (IntStream, LongStream, and DoubleStream, respectively).

int[] arr = {1, 2, 3};
IntStream stream = Arrays.stream(arr);
stream.forEach(System.out::println);

Interestingly, Java 8 also adds java.util.PrimitiveIterator. This provides the best of both worlds: compatibility with Iterator<T> via boxing along with methods to avoid boxing. PrimitiveIterator has three built-in interfaces that extend it: OfInt, OfLong, and OfDouble. All three will box if next() is called but can also return primitives via methods such as nextInt(). Newer code designed for Java 8 should avoid using next() unless boxing is absolutely necessary.

int[] arr = {1, 2, 3};
PrimitiveIterator.OfInt iterator = Arrays.stream(arr);

// You can use it as an Iterator<Integer> without casting:
Iterator<Integer> example = iterator;

// You can obtain primitives while iterating without ever boxing/unboxing:
while (iterator.hasNext()) {
    // Would result in boxing + unboxing:
    //int n = iterator.next();

    // No boxing/unboxing:
    int n = iterator.nextInt();

    System.out.println(n);
}

If you're not yet on Java 8, sadly your simplest option is a lot less concise and is almost certainly going to involve boxing:

final int[] arr = {1, 2, 3};
Iterator<Integer> iterator = new Iterator<Integer>() {
    int i = 0;

    @Override
    public boolean hasNext() {
        return i < arr.length;
    }

    @Override
    public Integer next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }

        return arr[i++];
    }
};

Or if you want to create something more reusable:

public final class IntIterator implements Iterator<Integer> {
    private final int[] arr;
    private int i = 0;

    public IntIterator(int[] arr) {
        this.arr = arr;
    }

    @Override
    public boolean hasNext() {
        return i < arr.length;
    }

    @Override
    public Integer next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }

        return arr[i++];
    }
}

You could get around the boxing issue here by adding your own methods for obtaining primitives, but it would only work with your own internal code.

3. Is the array converted to a list to get the iterator?

No, it is not. However, that doesn't mean wrapping it in a list is going to give you worse performance, provided you use something lightweight such as Arrays.asList.


I'm a recent student but I BELIEVE the original example with int[] is iterating over the primitives array, but not by using an Iterator object. It merely has the same (similar) syntax with different contents,

for (primitive_type : array) { }

for (object_type : iterableObject) { }

Arrays.asList() APPARENTLY just applies List methods to an object array that it's given - but for any other kind of object, including a primitive array, iterator().next() APPARENTLY just hands you the reference to the original object, treating it as a list with one element. Can we see source code for this? Wouldn't you prefer an exception? Never mind. I guess (that's GUESS) that it's like (or it IS) a singleton Collection. So here asList() is irrelevant to the case with a primitives array, but confusing. I don't KNOW I'm right, but I wrote a program that says that I am.

Thus this example (where basically asList() doesn't do what you thought it would, and therefore is not something that you'd actually use this way) - I hope the code works better than my marking-as-code, and, hey, look at that last line:

// Java(TM) SE Runtime Environment (build 1.6.0_19-b04)

import java.util.*;

public class Page0434Ex00Ver07 {
public static void main(String[] args) {
    int[] ii = new int[4];
    ii[0] = 2;
    ii[1] = 3;
    ii[2] = 5;
    ii[3] = 7;

    Arrays.asList(ii);

    Iterator ai = Arrays.asList(ii).iterator();

    int[] i2 = (int[]) ai.next();

    for (int i : i2) {
        System.out.println(i);
    }

    System.out.println(Arrays.asList(12345678).iterator().next());
}
}

No, there is no conversion. The JVM just iterates over the array using an index in the background.

Quote from Effective Java 2nd Ed., Item 46:

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.

So you can't get an Iterator for an array (unless of course by converting it to a List first).


Strictly speaking, you can't get an iterator of the primitive array, because Iterator.next() can only return an Object. But through the magic of autoboxing, you can get the iterator using the Arrays.asList() method.

Iterator<Integer> it = Arrays.asList(arr).iterator();

The above answer is wrong, you can't use Arrays.asList() on a primitive array, it would return a List<int[]>. Use Guava's Ints.asList() instead.


How does the above for-each loop work?

Like many other array features, the JSL mentions arrays explicitly and gives them magical properties. JLS 7 14.14.2:

EnhancedForStatement:

    for ( FormalParameter : Expression ) Statement

[...]

If the type of Expression is a subtype of Iterable, then the translation is as follows

[...]

Otherwise, the Expression necessarily has an array type, T[]. [[ MAGIC! ]]

Let L1 ... Lm be the (possibly empty) sequence of labels immediately preceding the enhanced for statement.

The enhanced for statement is equivalent to a basic for statement of the form:

T[] #a = Expression;
L1: L2: ... Lm:
for (int #i = 0; #i < #a.length; #i++) {
    VariableModifiersopt TargetType Identifier = #a[#i];
    Statement
}

#a and #i are automatically generated identifiers that are distinct from any other identifiers (automatically generated or otherwise) that are in scope at the point where the enhanced for statement occurs.

Is the array converted to a list to get the iterator?

Let's javap it up:

public class ArrayForLoop {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        for (int i : arr)
            System.out.println(i);
    }
}

then:

javac ArrayForLoop.java
javap -v ArrayForLoop

main method with a bit of editing to make it easier to read:

 0: iconst_3
 1: newarray       int
 3: dup
 4: iconst_0
 5: iconst_1
 6: iastore
 7: dup
 8: iconst_1
 9: iconst_2
10: iastore
11: dup
12: iconst_2
13: iconst_3
14: iastore

15: astore_1
16: aload_1
17: astore_2
18: aload_2
19: arraylength
20: istore_3
21: iconst_0
22: istore        4

24: iload         4
26: iload_3
27: if_icmpge     50
30: aload_2
31: iload         4
33: iaload
34: istore        5
36: getstatic     #2    // Field java/lang/System.out:Ljava/io/PrintStream;
39: iload         5
41: invokevirtual #3    // Method java/io/PrintStream.println:(I)V
44: iinc          4, 1
47: goto          24
50: return

Breakdown:

  • 0 to 14: create the array
  • 15 to 22: prepare for the for loop. At 22, store integer 0 from stack into local position 4. THAT is the loop variable.
  • 24 to 47: the loop. The loop variable is retrieved at 31, and incremented at 44. When it equals the array length which is stored in local variable 3 on the check at 27, the loop ends.

Conclusion: it is the same as doing an explicit for loop with an index variable, no itereators involved.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to arrays

PHP array value passes to next row Use NSInteger as array index How do I show a message in the foreach loop? Objects are not valid as a React child. If you meant to render a collection of children, use an array instead Iterating over arrays in Python 3 Best way to "push" into C# array Sort Array of object by object field in Angular 6 Checking for duplicate strings in JavaScript array what does numpy ndarray shape do? How to round a numpy array?

Examples related to iterator

Iterating over Typescript Map Update row values where certain condition is met in pandas How to iterate (keys, values) in JavaScript? How to convert an iterator to a stream? How to iterate through a list of objects in C++ How to avoid "ConcurrentModificationException" while removing elements from `ArrayList` while iterating it? How to read one single line of csv data in Python? 'numpy.float64' object is not iterable Python list iterator behavior and next(iterator) python JSON only get keys in first level

Examples related to foreach

Angular ForEach in Angular4/Typescript? How to use forEach in vueJs? Python foreach equivalent Get current index from foreach loop TypeScript for ... of with index / key? JavaScript: Difference between .forEach() and .map() JSON forEach get Key and Value Laravel blade check empty foreach Go to "next" iteration in JavaScript forEach loop Why is "forEach not a function" for this object?