Home  >  Article  >  Java  >  Detailed introduction to Iterable and Iterator in Java

Detailed introduction to Iterable and Iterator in Java

不言
不言forward
2018-10-08 15:37:532950browse

This article brings you a detailed introduction to Iterable and Iterator in Java. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

In Java, we can traverse the List collection in the following ways:

List<Integer> list = new ArrayList<>();
list.add(5);
list.add(23);
list.add(42);
for (int i = 0; i < list.size(); i++) {
    System.out.print(list.get(i) + ",");
}

Iterator it = list.iterator();
while (it.hasNext()) {
    System.out.print(it.next() + ",");
}

for (Integer i : list) {
    System.out.print(i + ",");
}

The first is an ordinary for loop, the second is iterator traversal, and the third It's a for each loop. The latter two methods involve iterator and iterable objects in Java. Next, let's take a look at the differences between these two objects and how to implement a for each loop in a custom class.

Iterator and Iterable

iterator is an iterator object in Java, which is the underlying dependency that can iterate over a collection such as List. The iterable interface defines a method that returns iterator, which is equivalent to encapsulating iterator. At the same time, classes that implement the iterable interface can support for each loop.

Iterator internal details

The main methods of the Iterator interface in jdk are as follows:

public interface Iterator<E> {
    boolean hasNext();
    E next();
}

Iterator defines the method of iterative access to the collection through the above two methods, and the specific implementation method Depending on different implementation classes, the specific collection class implements the methods in the Iterator interface to implement iteration.

It can be found that the Iterator interface is not implemented in List, but the Iterable interface is implemented. Further observation of the source code of the Iterable interface shows that it just returns an Iterator object.

public interface Iterable<T> {
  Iterator<T> iterator();
}

So we can use the following method to iterate the List (by calling the iterator() method)

Iterator it = list.iterator();
while (it.hasNext()) {
    System.out.print(it.next() + ",");
}

At the same time, if you implement the Iterable interface, you can also use the for each loop.

for each principle

In fact, the for each loop also relies on the Iterator iterator, but the syntax sugar provided by Java, the Java compiler will convert it into an Iterator iterator for traversal. We decompile the following for each loop:

 for (Integer i : list) {
       System.out.println(i);
   }

After decompilation:

Integer i;
for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(i)){
        i = (Integer)iterator.next();        
    }

You can see that Java's for each enhanced loop is implemented through iterator.

In-depth discussion of the relationship between Iterable and Iterator

I have a question, why not just put the hasNext() and next() methods directly in the Iterable interface, and other classes can implement them directly?

The reason is that some collection classes may have more than one traversal method. A class that implements Iterable can implement multiple Iterator internal classes, such as ListItr and LinkedList DescendingIteratorThe two internal classes implement bidirectional traversal and reverse order traversal respectively. By returning different Iterator, different traversal methods are implemented, which is more flexible. If you merge the two interfaces, you will not be able to return different Iterator implementation classes. ListItr related source code is as follows:

    public ListIterator<E> listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
    }

    private class ListItr implements ListIterator<E> {
        ...
        ListItr(int index) {
            // assert isPositionIndex(index);
            next = (index == size) ? null : node(index);
            nextIndex = index;
        }

        public boolean hasNext() {
            return nextIndex < size;
        }
        ...

As shown above, you can return the iterator by calling the list.listIterator() method (list.iterator() is just its default implementation )

DescendingIteratorThe source code is as follows:

    public Iterator<E> descendingIterator() {
        return new DescendingIterator();
    }
    private class DescendingIterator implements Iterator<E>     {
        private final ListItr itr = new ListItr(size());
        public boolean hasNext() {
            return itr.hasPrevious();
        }
        public E next() {
            return itr.previous();
        }
        public void remove() {
            itr.remove();
        }
    }

This iterator can also be used through list.descendingIterator().

Implement your own iterator

We now have a custom class ArrayMap, and now if we traverse it as follows for each:

ArrayMap<String, Integer> am = new ArrayMap<>();
am.put("hello", 5);
am.put("syrups", 10);

for (String s: am) {
   System.out.println(s);
}

Since we have not implemented hashNext and next abstract method, so it cannot be traversed.

Customized iterator class

We first customize an iterator class to implement hashNext and next methods, and use it as the internal class of ArrayMap. The relevant code is as follows:

   public class KeyIterator implements Iterator<K> {
        private int ptr;

        public KeyIterator() {
            ptr = 0;
        }

        @Override
        public boolean hasNext() {
            return (ptr != size);
        }

        @Override
        public K next() {
            K returnItem = keys[ptr];
            ptr += 1;
            return returnItem;
        }
    }

You can see that the traversal rule we specified in next is traversed based on the key value of ArrayMap. With the above iterator class, we can use the iterator method to traverse it externally. The traversal code is as follows:

ArrayMap<String, Integer> am = new ArrayMap<>();
am.put("hello", 5);
am.put("syrups", 10);
ArrayMap.KeyIterator ami = am.new KeyIterator();
while (ami.hasNext()) {
    System.out.println(ami.next());
}

As shown above, create a KeyIterator object for iterative access (note that the external class creates an internal class object).

Support for each loop

We cannot support for each loop access now because we have not implemented the iterable interface. First implement the Iterable interface in ArrayMap:

public class ArrayMap<K, V> implements Iterable<K> {

    private K[] keys;
    private V[] values;
    int size;

    public ArrayMap() {
        keys = (K[]) new Object[100];
        values = (V[]) new Object[100];
        size = 0;
    }
  ....
}

Then restart Write the iterator() method and return our own iterator object (iterator)

    @Override
    public Iterator<K> iterator() {
        return new KeyIterator();
    }

Note that our custom KeyIterator class must implement the Iterator interface, otherwise the type returned in the iterator() method will not match.

The above is the detailed content of Detailed introduction to Iterable and Iterator in Java. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:cnblogs.com. If there is any infringement, please contact admin@php.cn delete