Borrowing an Iterator

ArraySet now has to implement an iterator() method that returns an Iterator<T>.

public class ArraySet<T> implements Set<T> {
  // ... other methods implemented as before ...

  @Override
  public Iterator<T> iterator() {
    // We inherit this method from Iterable<T> since Set<T> extends Iterable<T>,
    // and now we have to implement it here.
    return null;
  }
}

We will write our own iterator next, but first we can get the enhanced for loop working by borrowing one. Java already provides a way to iterate over an array, so we can use a built-in iterator that traverses the backing array of ArraySet. Here is the implementation of iterator():

@Override
public Iterator<T> iterator() {
  return Arrays.stream(arr, 0, size).iterator();
}

Arrays.stream(arr, 0, size) creates a stream over the filled part of arr, from index 0 up to but not including size, so the empty trailing slots are left out. Calling .iterator() on that stream returns an Iterator<T> that produces those elements in order, and we return that iterator directly. For this to compile, you need to import java.util.Arrays and java.util.Iterator.

That one method is enough to make the enhanced for loop work:

Set<String> subscribers = new ArraySet<>();
// add some email addresses to the set

for (String email : subscribers) {
  sendNewsletter(email);
}

Next, we write an iterator ourselves. We need that for data structures that do not store their elements in an array.