Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplify writing custom iterators in Java

Writing iterators for custom collections in Java is quite complicated, because instead of writing straight-forward code that provides one element after the other, you essentially have to write a state machine:

public class CustomCollection<T> implements Iterable<T>
{
    private T[] data;
    private int size;

    @Override
    public Iterator<T> iterator()
    {
        return new Iterator<T>()
        {
            private int cursor = 0;

            @Override
            public boolean hasNext()
            {
                return cursor < size;
            }

            @Override
            public T next()
            {
                return data[cursor++];
            }

            @Override
            public void remove()
            {
                throw new UnsupportedOperationException();
            }
        };
    }
    // ...
}

For collections more complicated than an array list or a linked list, getting these state machines correctly is a daunting task. In fact, the C# design team deemed writing custom iterators complicated enough to introduce special language support (yield return) for letting the compiler build the state machines.

Is something like yield return coming in the next version of Java? Or are there any library solutions that make my life easier when it comes to writing my own iterators in Java?

like image 621
fredoverflow Avatar asked Feb 24 '23 19:02

fredoverflow


2 Answers

No, Java doesn't have anything like yield. As far as libraries, Guava has a number of helpful classes to make certain kinds of iterators easy to write:

  • AbstractIterator just requires you to implement a T computeNext() method.
  • AbstractLinkedIterator requires you to implement T computeNext(T previous).

AbstractIterator could be used for this as follows:

return new AbstractIterator<T>() {
  private int index = 0;

  protected T computeNext() {
    return index == size ? endOfData() : data[index++];
  }
};

You could also use Arrays.asList as Amir suggested, or even do something like this:

private final List<T> listView = new AbstractList<T>() {
  public int size() {
    return data.length;
  }

  public T get(int index) {
    return data[index];
  }
};

public Iterator<T> iterator() {
  return listView.iterator();
}
like image 155
ColinD Avatar answered Mar 02 '23 14:03

ColinD


Maybe I am just not understanding your questions. Can you not do return Arrays.asList(data).iterator()

like image 40
Amir Raminfar Avatar answered Mar 02 '23 14:03

Amir Raminfar