1. Overview
Iterable interface provides a contract which is, if implemented the object will be allowed as a target of for-each loop. Collection interface extends Iterable interface and hence all the Collection implementations are target of for-each loop. Iterable interface had only one abstract method iterator() that returns Iterator. But as of Java 8 two additional methods are added i.e. forEach() and spliterator(). Both this methods are default methods.
2. Content
In this article, we will be discussing this two methods i.e. forEach() and spliterator() and in addition to that we will also discuss external iterator and internal iterator too.
2.1. forEach() method
default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } }
forEach() method is a default method added in Iterable interface. Consumer performs specified action on every element until all elements are processed or the action throws Exception. The iteration order is defined by the implementing class of the container. forEach() method throws NullPointerException if the specified action is null.
Below examples prints the invoice price of every transaction.
transactions.forEach(txn -> System.out.println(txn.invoice().price()));
A good thing about forEach() method is that we do not need to use for each loop to iterate elements. forEach() method takes care of that. This means it is internal iteration. Stream API are implemented with internal iteration. We will talk about it a-lot in upcoming articles.
2.2. External Iterator
External iterator is iterator used by client to iterate the elements in container and perform some action on it. Client uses pull mechanism to get the data out of container. External iterators forces client to say what needs to be done and how to do it. Example : for loop, while loop.
2.3. Internal Iterator
As compared to external iterator, internal iterator is controlled by framework. Client just need to specify what needs to done and iteration is taken care of by the framework itself. forEach() method is classic example of internal iteration. Another example is stream apis introduced in Java 8.
Below is the code of getting the total amount of all the transactions. Stream APIs uses internal iteration concept. We just need to pass the behavior and rest is taken care itself.
transactions.stream() .map(txn -> txn.invoice().price()) .reduce(Money::plus) .get();
2.4. forEach() using Lambda Expression
Consumer interface is specified as a parameter to forEach() method. As Consumer interface is a functional interface we can use lambda operator to specify the action.
transactions.forEach(txn -> System.out.println(txn.invoice().price()));
2.5. forEach() using Method Reference
In the case where the method already exists to perform the operation, method reference is preferred over the lambda operator.
cities.forEach(System.out::println);
2.6. spliterator() method
spliterator() method returns Spliterator. “Duh”. Spliterator is an object for traversing and partitioning the elements of a source, where a source can be array, Collection, IO channel or generator function. Spliterator can also be called splittable iterator. A Spliterator can traverse elements individually or in bulk. I will write more about Spliterator in upcoming articles as it is vast topic on its own.
3. Conclusion
In this article, we learned new methods added in Iterable interface with examples. We also learned about external and internal iterators and how both of them can be used by client.