Zach Cochran
by Zach Cochran
4 min read

Categories

Tags

Today I learned how to use Iterators to iterate through collections.

Like I mentioned in my post from a few days ago, the Collection interface in java implement the Iterable interface, which in tern implements the Iterator interface. Because of this, we’re able to iterate over the contents of our collections to look through the contents of what’s stored.

In the example that I used back then, I’m pretty sure I handled things using a for each method, rather than handling the problem using an iterator (as it was what made more sense to me at the time). Behind the scenes, the for each method is actually using an iterator to handle its implementation.

But what about the cases where you might want to be removing things from the collection based on specific scenarios? I can’t do that normally when I iterate over a list as I have no way to cleanly delete the item. But explicitly using an iterator gives you this capability.

Using Iterators

Using an iterator is easy if you are working with something like a collection as it is already being implemented for you. In order to take advantage of the capability, you need to create a new Iterator object from your collection object:

       List<Product> products = new ArrayList<>();
       products.add(ProductFixtures.table);
       products.add(ProductFixtures.chair);
       products.add(ProductFixtures.lamp);

       Iterator<Product> iterator = products.iterator();

In this case I’ve now created a new iterator into that products List collection.

In order to start iterating through it, I just need to set up a while loop using the Iterator method hasNext to constantly scan to see if there are more items in the collection:

       while (iterator.hasNext()) {
           System.out.println(iterator.next());
       }

In this case we’ll iterate through the products List and print out each of the products:

net.fuzzylimes.blog.lists.Product{weightInLbs=45.0, name='Old Table'}
net.fuzzylimes.blog.lists.Product{weightInLbs=10.0, name='Hard Chair'}
net.fuzzylimes.blog.lists.Product{weightInLbs=5.0, name='Dim Lamp'}

It’s really that simple to use.

Iterator only has four basic methods to it:

  • hasNext() - returns a boolean whether or not there are anymore items in the collection
  • remove() - removes the current object from the collection object (more on this soon)
  • next() - gets the next value from the collection and moves where the iterator is pointing
  • forEachRemaining() - Another way of iterating over the collection

If I wanted to do what I did above using the forEachRemaining, I could do the following:

   iterator.forEachRemaining(n -> {
       System.out.println(n);
   });

One thing to note here is that when you’ve completed iterating to the end, that is your pointer has reached the end of the collection, there’s no way for you to wrap around back to the beginning. You will need to initialize the iterator again to start over.

Just to illustrate this point, I’ll update the code from above to print our whether or not the iterator hasNext after going through the List once:

   public void arrayIteratorGetNextFalse() {
       List<Product> products = new ArrayList<>();
       products.add(ProductFixtures.table);
       products.add(ProductFixtures.chair);
       products.add(ProductFixtures.lamp);

       Iterator<Product> iterator = products.iterator();

       while (iterator.hasNext()) {
           System.out.println(iterator.next());
           iterator.remove();
       }

       Assert.assertFalse(iterator.hasNext());
   }

Removing as you go

As I mentioned at the beginning, really the big thing about using the Iterators explicitly is that you have the ability to remove items as you’re going. From what I read around the internet, this seems to be the big reason to use them in the first place.

So let’s look at the example from above again. Let’s say that while I’m iterating through the products List I want to remove out any products that are more than 30lbs in weight (because I can’t be bothered to hurt my back). I could do the following to get rid of them:

   public void arrayIteratorRemove() {
       List<Product> products = new ArrayList<>();
       products.add(ProductFixtures.table);
       products.add(ProductFixtures.chair);
       products.add(ProductFixtures.lamp);

       Iterator<Product> iterator = products.iterator();

       while (iterator.hasNext()) {
           Product val = iterator.next();
           if (val.getWeightInLbs() > 30) {
               iterator.remove();
           }
       }

       System.out.println(products);
   }

Ironically enough, that example above actually throws a notice in IntelliJ telling that things could be written much simpler using the Collections removeIf() method:

       products.removeIf(val -> val.getWeightInLbs() > 30);

I guess it just comes down to a matter of personal preference and readability? Knowing this now, I’m not really sure when I would ever choose to use an explicit iterator over just going through the List myself.

List Iterators

As I was doing some research for all of this, I found out that there are ListIterators that behave much in the same way that normal Iterators work, but with a few different bonuses.

This post is already starting to get long though, so I think I’ll save that for tomorrow.

Conclusion

To me, it almost seems like using explicit Iterators is redundant at this point. It seems to me that pretty much everything uses them already behind the scenes, with less effort on the users ends… so I’m not sure how much I’ll use them.

Hopefully you found this useful and were able to learn something along with me. As always, sample code from this post is available in my github repo.

💚 A.B.L.