JB Header
Java 8 Internal Iterators vs External Iterators
This article explains external and internal iterators with examples, compares them and then shows how internal iterators are meant to be used with Java 8 Streams API. External Iterators Definition(or Active Iterators) With external iterators responsibility of iterating over the elements, and making sure that this iteration takes into account the total number of records, whether more records exist to be iterated and so on lies with the programmer. A brief look at the evolution of external iterators in java Lets look into some external iterators which we have been using as java language evolved over the years.

Starting with Enumerations, iterations then moved on to Iterators(remember iterator(), next() or hasNext() methods for iterators). Then came Java 5 and along with came the enhanced for-loop which made use of generics to make iteration a lot easier. Lets see an example of enhanced for-loop introduced in Java 5 which uses the Iterable interface (you might already be familiar with this one) -
Enhanced for-loop example (uses external iterator)
import java.util.*;
public class ExternalIterator {
 public static void main(String args[]){
  List<String> namesList=Arrays.asList("Tom", "Dick", "Harry");
  for(String name:namesList){
    System.out.println(name);
  }
 }
}
However, though we are explicitly not invoking hasNext() or next() methods while iterating over the list above, still the underlying code which makes this iteration work uses these methods. This implies that the complexity behind these operations is hidden from the programmer but it still exists. And it still is an active iterator.

All the above ways - Enumerations, Iterators and enhanced for-loop seem the natural way of iterating right!! Well yes, but then managing the iterations still remains the programmer's job. Well not anymore with the advent of Internal Iterators in Java 8. Internal Iterators(or Passive Iterators) Internal Iterators manage the iterations in the background. This leaves the programmer to just declaratively code what is meant to be done with the elements of the Collection, rather than managing the iteration and making sure that all the elements are processed one-by-one.

Lets see how simple it is to say print all elements in an ArrayList in Java 8 using an example of internal iterator based forEach loop -
Example of internal iteration based forEach loop in Java 8
import java.util.*;
public class InternalIterator {
  public static void main(String args[]){
  List<String> namesList=Arrays.asList("Tom", "Dick", "Harry");
    namesList.forEach(name -> System.out.println(name));//Internal Iteration
  }
}
In the above code, we are just telling the forEach method what to do(i.e. print) with each String in the namesList list using a lambda expression( In case you are not familiar with lambda expressions you can read the tutorial hereLink to Lambda Expressions Tutorial).

All the work of iterating over the list of names one by one and printing them is taken care of internally by the runtime, leaving us with just declaratively defining only what is to be done i.e. print the names. Advantage of internal iterators over external iterators
  • Improved code readability as its declarative in nature
  • Concise code as multiple lines of code for external iterators is reduced to just one or two lines of code in case of internal iterators
  • Simplified implementation/less defects as code written by programmer is very less, chances of bugs creeping into the iteration logic are not there.
Point in favor of external iterators If you want more control over the iteration, and want to perform some check or operation for a particular index then external iterators are preferred over internal ones. Internal Iteration Using Streams Its important to understand what role the internal iterator plays in the Java 8 scheme of things. In the previous code example for forEach method, we could have made use of the java 8 Streams API to first create a Stream of elements in the List and then pipeline the stream into a forEach method like this -
Java 8 way to create a stream and then iterate internally
namesList.stream().forEach(name -> System.out.println(name));//Internal Iteration
The forEach method comes under the category of terminal operationsClick to Read Tutorial explaining intermediate & terminal Stream operations when working with streams i.e. it ends the chain of pipelined operations to produce a result. Note - You can also use internal iterators with parallelStream() method instead of a stream to improve on the performance. Summary We looked at the external iterators being used uptil Java 7, then understood what are internal iterators with Java 8's forEachmethod, then saw few advantages of internal iterators over external ones, and finally saw how forEach works when used with java 8 Streams API.