Iterable and Iterator in Java4 min read
A lot of people feel confused about the Iterator and Iterable interfaces in Java, because they have very similar names and sometimes they work together which makes people hardly tell them apart. In this article, we are going to elucidate the difference between them and see how they can be used through some examples.
In short, the Iterable interface belongs to the java.lang package, while the Iterator interface is a part of java.util package. An Iterable is a simple representation of a series of elements that can be iterated over, but it doesn’t provide any iteration state to get the “current element”. An Iterator, on the other hand, allows you to iterate over elements of iterable objects. You can iterate through each element of the collection by using the hasNext() and next() methods of this interface.
Table of Contents
Iterable and Iterator Interfaces
For the Iterable interface, there are some common methods:
default void forEach(Consumer<? super T> action): perform the given function on each element of theIterableuntil all elements have been processed or an exception occurred.default Spliterator<T> spliterator(): creates aSpliteratorover the elementsIterator<T> iterator(): returns anIteratorover elements of typeT.
Any class implements this interface needs to override the iterator() method.
Here are some frequently used methods of the Iterator interface:
E next(): returns the next element with typeEin the iteration.boolean hasNext(): returnstrueif the iteration still has one or more elements.void remove(): removes the element from the underlying collection which is the last element returned fromIterator.
Any class implements the Iterator interface need to override the next() and hasNext() method.
As you can see, the relationship between the Iterable and Iterator interface is close, the implementation of Iterable is one that provides Iterator of itself.
A Typical Example
Every class in the Collection interface indirectly implement the Iterable interface, that’s why we can use every method defined in the Iterable interface, for example, we have a List like this:
List<Integer> nums = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
nums.forEach(/* some code */);
nums.iterator();
nums.spliterator();
For more specific, the ArrayList class implements the List interface, the List interface implements the Collection interface, the Collection interface extends the Iterable interface.
The crux here is here any collection implements Iterable interface gives you the iterator() method, which returns an Iterator and we can use this to iterate through each element of the collection:
public static void main(String[] args) {
List<Integer> nums = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
Iterator<Integer> iterator = nums.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
// output: 1 2 3 4 5
}
We can also make the use of the for-each loop, which internally calls the iterator() method on an object:
public static void main(String[] args) {
List<Integer> nums = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
for (Integer num : nums) {
System.out.print(num + " ");
}
}
The forEach() method can also be used to iterate over a collection, which also uses for-each internally:
public static void main(String[] args) {
List<Integer> nums = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
nums.forEach(e -> System.out.print(e + " ")); // 1 2 3 4 5
}
More Iterator examples
The Iterable doesn’t maintain the current state of the iteration, but an Iterator does. With an Iterator, we can obtain the current element, moving forward if there are still some elements, and remove an element from the underlying collection if necessary:
public static void main(String[] args) {
List<Integer> nums = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
Iterator<Integer> iterator = nums.iterator();
while(iterator.hasNext()) {
int i = iterator.next();
System.out.print(i + " ");
if (i % 2 == 0) {
iterator.remove();
}
}
System.out.println();
for(Integer i: nums) {
System.out.print(i + " ");
}
/* output:
1 2 3 4 5 6 7 8 9 10
1 3 5 7 9
*/
}
In this example, we just simply create a list with ten integer from 1 to 10. We then create an iterator from this collection, it iterates until there is no element left, we print each element on each iteration and then removes the even elements from the underlying collection with the remove() method.
Notice that each time you call the next() method, it will return the next element in the iteration, hence you need to pay a little attention to this:
while (iterator.hasNext()) {
System.out.println(iterator.next());
if(iterator.next() % 2 == 0) {
iterator.remove();
}
}
/* it will just print 1 3 5 7 9 */
Wrapping up
Let’s summarize what we have learned:
- The
Iterableinterface gives you a representation of a series of elements that can be iterated through, but we need anIteratorto get the iteration state. - The
Iterableitself has a method returns anIterator. - The
Collectioninterface extendsIterable, that’s why you can directly use theIterable‘s methods on any subclass belong to this Collection interface, whose elements are intrinsically iterable. - Classes implementing
Iterablemust overrideiterator()method, while it’s obliged to overridenext()andhasNext()methods if a class implementsIterator. - You cannot modify elements with an Iterable, but an Iterator can give you the current state of the iteration with the
next()andhasNext()methods, and remove an element from the underlying collection with theremove()method.