Ways of iterating

As the Java language has grown, so has the number of ways it can iterate over items. Here are some examples as reminders.
import java.util.ArrayList;
import java.util.stream.IntStream;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.Vector;

public class IterationExamples {
  
  public static void main(String... args) {
    IterationExamples examples = new IterationExamples();
    examples.forLoopWithIntegerIndex();
    examples.enhancedFor();
    examples.explicitIterator();
    examples.listIterator();
    examples.overAnEnumeration();
    examples.simpleDoWhileLoop();
    examples.streamsAndLambdas();
  }
  
  /** Common error: off-by-one in the index value. */
  void forLoopWithIntegerIndex(){
    logTitle("Normal for loop.");
    for(int idx=0; idx < NAMES.size(); ++idx){
      log(NAMES.get(idx));
    }
  }

  /** More compact, less error-prone than the for-loop with an int index. */
  void enhancedFor(){
    logTitle("Enhanced-for loop. JDK 1.5+");
    for(String name : NAMES){
      log(name);
    }
  }
  
  /** 
   A common reason for using an Iterator is to remove items from the collection.
   With a normal enhanced-for loop, you can't modify the underlying collection
   while you're iterating over it. 
  */
  void explicitIterator(){
    logTitle("Explicit Iterator. JDK 1.5+");
    Set<String> letters = new LinkedHashSet<>();
    letters.add("alpha"); 
    letters.add("beta"); 
    letters.add(""); // an empty string 
    letters.add("gamma");
    log("Before: " + letters);
    
    //now remove any empty strings from the collection
    Iterator<String> iter = letters.iterator();
    while(iter.hasNext()){
      if (iter.next().trim().length() == 0){
        //this only works if the collection supports 'remove'
        iter.remove();
      }
    }
    log("After: " + letters);
    
    /*
     This second style has the advantage that the iterator object is 
     confined to the for-loop; however, it's not as legible as the 
     previous style.
    */
    logTitle("Explicit iterator with a for-loop.");
    for (Iterator<String> iter2 = letters.iterator(); iter2.hasNext();){
      log(iter2.next());
    }
  }

  /** ListIterator is for Lists only. */
  void listIterator(){
    logTitle("ListIterator can add-remove-change. JDK1.5+");
    List<Integer> years = new ArrayList<>();
    years.add(1775); 
    years.add(1925);
    years.add(1929);
    log("Before: " + years);
    ListIterator<Integer> iter = years.listIterator();
    while (iter.hasNext()){
      Integer value = iter.next();
      if (value >= 1900){
        iter.set(value - 1);
      }
      else if (value < 1800){
        iter.remove();
      }
    }
    log("After: " + years);
  }
  
  /** 
   Enumerations are used by older APIs.
   When defining new code, you should almost always use Collections and Maps instead. 
  */
  void overAnEnumeration(){
    //Vector is an older class, usually avoided in new code
    Vector<String> v = new Vector<>(); 
    v.add("alpha");
    v.add("beta");
    v.add("gamma");
    Enumeration<String> e = v.elements();
    logTitle("Enumeration, with a while loop.");
    while (e.hasMoreElements()){
      log(e.nextElement());
    }
  }
  
  /**
   do-while isn't used often. 
   It differs from the while-loop in the placement of the boolean test.
   In a do-while loop, the loop body is executed at least once. 
  */
  void simpleDoWhileLoop(){
    logTitle("Do-while.");
    int countDown = 5;
    do {
      log(countDown);
      --countDown;
    }
    while(countDown > -1);
  }

  /** @since Java 8 */
  void streamsAndLambdas(){
    logTitle("Iterable.forEach(Consumer). JDK 8+");
    //Iterable now has a functional-friendly forEach method that 
    //takes a Consumer, so you don't even need an intermediate stream
    NAMES.forEach(name -> log(name));

    logTitle("Explicit stream with a lambda expression. JDK 8+");
    NAMES.stream().forEach(name -> log(name));
    
    logTitle("Explicit stream with a method reference expression. JDK 8+");
    NAMES.stream().forEach(System.out::println);

    logTitle("Using a stream in a second style, for N-line methods. JDK 8+");
    NAMES.stream().forEach(name -> {
      log(name.toLowerCase());
      log(name.toUpperCase());
    });
    
    logTitle("IntStream has a compact way of defining ranges of integers.");
    IntStream.range(10,20).forEach(i -> log(i));
  }
  
  private List<String> NAMES = Arrays.asList("Ann", "Bob", "Charles", "Diane");
  
  private static final void log(Object thing){
    System.out.println("  " + thing.toString());
  }
  
  private static final void logTitle(Object thing){
    System.out.println(thing.toString());
  }
}
 

See Also :
Iterate without an index
Use for each liberally
Remove from a collection