Why doesn't the standard Java iterator have peek()?

Viewed 7459

Is there any particular reason the basic Java iterator was programmed not to have a function like peek(), which would return the next element without advancing the iterator?

3 Answers

Why doesn't the standard Java iterator have peek()?

  1. Because peek() is not part of the Iterator design pattern as it is normally described.

  2. Because the vast majority of iterator use-cases don't require it. Forcing all implementations (including a myriad custom / 3rd party classes) to implement an unnecessary method would be a bad idea.

  3. Because the peek() method has potential impacts on the semantics for iterators of lazy data sources.

  4. Because implementing peek() affects the efficiency (memory, CPU) of a iterator in some circumstances. Whether you actually use it or not.

  5. Because peek() would in some obscure circumstances lead to a memory leak.

  6. Because ... KISS.

But ultimately, the real reason is ... because they designed it that way back in the year ~2000. And we weren't in the room when the design debates took place1.

1 - For what it is worth, it seems that most2 other languages have made the same decision for their standard iterator API. Rust seems to be an exception to this; see https://doc.rust-lang.org/std/iter/struct.Peekable.html.

2 - ... based on a highly non-scientific "survey" using Google search.


If you want an iterator abstraction that provides peek() as well, you can extend the Iterator interface and implement the iterators for yourself. Indeed an general purpose iterator-with-peek can easily be implemented as a wrapper for a regular Iterator.

Or look for a 3rd-party API / implementation(s); e.g. Guava, Apache Commons, etc.

The following example implements an Iterator with a peek method. The implementation of remove is left for the reader.

import java.util.Iterator;

/**
 * An Iterator with a peek method for just one value.
 */
public class PeekIterator<T> implements Iterator<T>
{
  private Iterator<T> iterator;

  public PeekIterator (Iterator<T> iterator) { this.iterator = iterator; }

  private boolean peeked = false;
  private T peeked_value = null;

  public boolean hasNext () { return iterator.hasNext () || peeked; }

  public T next ()
  {
    T value;
    if (peeked) {
      peeked = false;
      value = peeked_value;
    }
    else
      if (iterator.hasNext ())
        value = iterator.next();
      else
        value = null;
    return value;
  }

  public T peek ()
  {
    T value;
    if (peeked)
      value = peeked_value;
    else {
      peeked = true;
      if (iterator.hasNext ())
        peeked_value = iterator.next ();
      else
        peeked_value = null;
      value = peeked_value;
    }
    return value;
  }
}

If you really need an iterator with peek(), why not use a LinkedList as your initial datastructure? It provides .peek() and .pop() to retrieve the head.

Related