Iterable Interface in Java
The Iterable interface is present in java.lang.Iterable package. It was introduced in JDK 1.5. It allows users to iterate through elements sequentially from a collection. It returns each element of the collection one after the other, beginning from the front and moving forward. There are three ways in which elements can be iterated in Java: the enhanced for loop, the forEach() method, and the iterator() method. The Collection interface extends the Iterable interface thus, all the classes implementing the Collection interface are iterable.
Introduction to Iterable in Java
Iterable in Java is an interface that allows collection elements to be accessed individually. Using Iterable, elements of collections like arrays, sets, queues, maps, etc. can be transversed easily.
The Collection framework extends the Iterable interface. Thus, all the classes implementing the collections framework also implement the Iterable interface, and objects of these classes can use Java's Iterable feature.
By using Iterator, we can access each item in the collection, one item at a time. Here, we have an array of 5 elements, iterator named iter of this array returns each element of the array one by one starting from 0^th^ index.
Iterator
Iterator and Iterable both interfaces sound similar and are often confusing. Any class that implements an Iterable interface overrides the iterator() method present in the Iterable interface. This iterator() method calls an Iterator interface, which returns an iterator. This iterator is used to iterate over an object of that class. The Iterator interface has four methods namely next(), hasNext(), remove() and forEachRemaining().
Syntax to Implement Iterable
Import java.lang.Iterable package to access Iterable.
Declaration of an Iterator
We create an object of Iterator named iter. iter will return data of the specified type in Angular Brackets (<>). If not mentioned, it returns an object.
Initialization of an Iterator
Obj is the name of a collection like Stack, Queue, HashMap, etc. DataType is the type of data filled in the DataStructure, such as String, Integer, etc. If we don't mention DataType in the Iterator, it will return an Object.
For example:
In the above example, a Queue named myQueue is created, which is going to store a String in it. We create an Iterator named iter that returns a String. Queue class Overrides iterator method from Iterable Interface, that we are calling on myQueue an Object of Queue Class.
How Java Iterable Works?
Collection can be array, list, set, etc. When collection calls the Iterable interface, it calls the iterator() method. This method returns the Iterator of a specified type. Now we check the Iterator to see if it has any elements using the hasNext() method; if it returns true, we call the next() method to retrieve the element; otherwise, we terminate the loop. Let us take an example to understand the workings of an Iterator.
We create an object of an Iterator on a Stack and check if the Stack has elements that have not yet been visited using the hasNext() method. If it returns true, we call next() and retrieve that element. If it returns false, it implies we visited all the elements of the Stack or the Stack is empty. Thus, we exit from the while loop.
Output:
Objects of Iterable can be Iterated in three ways:
- Enhanced for loop(for-each loop)
- Iterable forEach loop
- Iterator<T> interface
Iterate an Iterable With the for-each Loop
The first way to iterate the elements of a Java Iterable is using Enhanced for loop. It is also known as a for-each loop.
Objects of Classes implementing Collection Interface can be transversed using the for-each loop as Collection interface extends Iterable interface. Elements of the collection can only be read. They cannot be removed, updated, or added to the collection. Index of the element also cannot be accessed. We cannot skip any index or visit alternate positions.
Syntax for enhanced for loop:
Where DataType is DataType of the variable_name, type of data stored in the Collection. CollectionName is the name of the Collection to be iterated.
Example:
Output:
We create a 2D array with rows and columns. Elements of this array are retrieved using nested for each loop. Array, Stack, Queue, Map, Set, etc. can be iterated using for-each loop.
Iterate an Iterable via its forEach() Method
The forEach() method uses Lamda Expression as a parameter. This Expression is called for each element of the Collection. The forEach() method cannot be used to update, add or remove elements of the collection. We can read elements of the collection and print them.
Syntax for forEach() Method
Collection_name is the name given to any collection, variable_name is the name to be given to the element inside the collection. -> is known as Lamda Expression.
Example
Output:
Printing even numbers from a stream of numbers. filter checks if the number is even. If the number is even then action is performed on the number.
Iterate an Iterable via an Iterator
Elements of Java Iterable can be iterated by calling the iterator() method that returns the Iterator.
Iterator Interface in Java has 4 methods:
- next() - It returns the next item in the collection. If all the collection elements are transversed or the collection is empty, it throws a NoSuchElementException.
- hasNext() - it returns a boolean. If all the collection items are covered, then it returns false; else, it returns true.
- remove() - This method removes the last element returned by the next() method. If the next() method is not called, then it throws an IllegalStateException. If the iterator doesn't support remove operation for that collection, then it throws the UnSupportedOperationException. remove() method must be called only once, for one next() call.
- forEachRemaining(CakeShop<String> action) - It performs the given action for all the remaining elements in the collection, in sequential (one by one) method.
Syntax:
Declaration of an Iterator
An iter is an Iterator object, which returns the specified DataType element in the Angular brackets.
Initialization of an Iterator
Obj is the collection name. The Obj class overrides the iterator method to an Iterable Interface. This method is called to create an iterator of Obj.
Example:
Output:
Student data is stored in a HashMap named Student. This data is printed using the iterator() method.
Iterable Interface Definition
The Iterable interface in Java has three methods, out of which only the iterator() method needs to be implemented. The other two have default implementations. The definition of Java Iterable Interface is given below:
Note: T in the above interface refers to the type of element returned by the Iterator.
Methods of Iterable
Iterable has 3 methods:
- void forEach(Consumer<? super T> action) - It acts as each item of the Iterable until all the items are processed or the method throws an exception.
- IteratorT> iterator()—It calls the Iterator Interface. The interface returns an iterator, which is used to iterate the elements in the container and perform some action on them.
- Spliterator<T> spliterator() - It creates a Spliterator over the items described by the Iterable. A spliterator is an object for traversing and partitioning the elements of a collection, where a collection can be an array, set, tree, or generator function. Spliterator can also be known as a splittable iterator. A Spliterator can traverse elements individually or all together.
Implementations of Iterable in Java
The Java Iterable interface (java.lang.Iterable) is among the root interfaces of the Java Collections API. Therefore, several classes in Java implement the Java Iterable interface. These classes can thus have their internal elements iterated.
Implementing the Iterable Interface
- Let us take an example to understand the implementation of the Iterable Interface in our own class CakeShop.
- We create a class CakeShop that implements Iterable. We create an ArrayList to store different types of cakes, and int variable totalFlavors to keep count of all types of cakes.
- addCake() method adds the cake flavor to the cakeFlavors ArrayList. As the CakeShop class implements Iterable, it must Override the iterator() method and return the Iterator of String type.
- This iterator can be used to iterate the objects of the CakeShop class. Iterator is also used in the back-end when we call for-each loop. Thus, most of the code is hidden and some part of it is present in the implementation of our class so that, in the main method code is short and clean.
- While Iterating currentIndex starts from 0 and goes till totalFlavors-1. hasNext() method returns a boolean. It returns true if currentIndex is less than totalFlavors; else, it returns false.
- next() method returns value in ArrayList at currentIndex. If hasNext() is false, it throws an exception.
Main Method:
Output:
We first create an object of CakeShop. We add different types of cake flavors to it using the addCake() method. Since the CakeShop class implements Iterable, we can call it the iterator() method. So, we create an object of Iterator named iter of String type and call iterator() method that returns an Iterator for CakeShop object named menu. Thus, if hasNext() is true while loop calls next() and print its value. If hasNext() is false while loop is terminated.
Difference between Iterator and Iterable in Java
Iterable Interface | Iterator Interface |
---|---|
Collection Framework extends Iterable Interface. Thus, Objects of classes implementing Collection Interface can be iterated. These classes Override the iterator() method which calls the Iterator interface. | Iterator interface returns an iterator of a specific class to transverse over a collection of elements. To iterate, hasNext() and next() methods are used in a loop. |
Iterable interface is located in java.lang.Iterable | Iterator interface is located in java.util.Iterator |
Classes that implement the Iterable interface need to override the iterator() method. | Classes that implement Iterator interface need to override hasNext(), next() and remove() methods. |
Iterable doesn't store any iteration state. Iteration state is the pointer to the element in a collection which the iterator is going to return next. | Iterator instance maintains the iteration state. This implies the user can check if the next element exists, move forward to the next element, etc. |
The Iterable method produces a new instance for an Iterator every time it is called. | Iterator instance maintains the iteration state. |
Iterable Interface has 3 methods i.e. iterator(), spliterator() and forEach() | Iterator has 4 methods i.e. next(), hasNext(), remove(), foreachRemaining(). |
For Iterable, we can move only in the forward direction. | Iterator's sub-instance like ListIterator can move in both directions i.e. forward and backward. |
Advantages of Iterable in Java
- Iteration is made easy using for-each loop.
- All the classes of Collection Interface can be transversed easily as it implements Iterable Interface.
- Elements can be read, removed, or operations can also be performed with them.
- It is considered to be the Universal Cursor for the Collection API.
- Methods are easy to use and implement.
Limitations of Iterable in Java
- We can move only in a forward direction while iterating. Reverse transversal is not possible.
- We can either read or remove elements. Both cannot be performed simultaneously. Also, Fail-Fast iterators throw in Java, if there is structural modification like addition, removal, updation of elements of the collection.
- Replacement or extension of objects is not facilitated.
- Elements cannot be added to the collection using an iterator.
- Java Iterator supports only Sequential transversal. We cannot skip elements or visit only even or odd positions in a collection.
- The for-each loop is slower as for every iteration it calls the iterator() method.
Conclusion
- Any class implementing an Iterable Interface overrides the iterator() method, which returns an Iterator that allows the user to iterate through that class's collection.
- Iterable and Iterator interfaces are different and should not be confused with.
- The Collection Interface extends the Iterable interface; thus, all its classes implement the iterator() method.
- Iterable provides three methods namely iterator(), spliterator() and forEach().
- Iterator facilitates four methods namely next(), hasNext(), remove(), foreachRemaining().