Creating your own Iterable structure for use loop


Creating your own Iterable structure for use with Iterator or for-each loop

To ensure that our collection can be iterated using iterator or for-each loop, we have to take care of following steps:

  • The stuff we want to iterate upon has to be Iterable and expose iterator().
  • Design a java.util.Iterator by overriding hasNext(), next() and remove().

I have added a simple generic linked list implementation below that uses above entities to make the linked list iterable.

package org.algorithms.linkedlist;
 
import java.util.Iterator;
import java.util.NoSuchElementException;
 
public class CustomLinkedList<T> implements Iterable<T> {
    Node<T> head, current;
 
    private static class Node<T> {
        T value;
        Node<T> next;
 
        Node(T value) {
            this.value = value;
        }
    }
 
    public CustomLinkedList(T value) {
        head = new Node<>(value);
    }
 
    public Iterator<T> iterator() {
        return new CustomLinkedListIterator();
    }
 
    private class CustomLinkedListIterator implements Iterator<T> {
        Node<T> node = head;
 
        @Override
        public boolean hasNext() {
            return node != null;
        }
 
        @Override
        public T next() {
            if (!hasNext())
                throw new NoSuchElementException();
            Node<T> prevNode = node;
            node = node.next;
            return prevNode.value;
        }
 
        @Override
        public void remove() {
            throw new UnsupportedOperationException("Removal logic not implemented.");
        }
    }
 
    public void add(T value) {
        Node<T> current = head;
        while (current.next != null)
            current = current.next;
        current.next = new Node<>(value);
    }
}
 
class MyApp {
    public static void main(String[] args) {
        CustomLinkedList<String> myList = new CustomLinkedList<>("A");
        myList.add("B");
        myList.add("C");
        myList.add("D");
 
        // Test #1
        System.out.println("Using Iterator:");
        Iterator<String> iterator = myList.iterator();
        while (iterator.hasNext()) {
            String element = iterator.next();
            System.out.print(element + " ");
        }
 
        // Test #2
        System.out.println("\n\nUsing for-each:");
        for (String data : myList) {
            System.out.print(data + " ");
        }
    }
}
 

Output

Using Iterator:
A B C D 

Using for-each:
A B C D 

This will run in Java 7+. You can make it run on Java 5 and Java 6 also by substitutin

LinkedList<Integer> list = new LinkedList<>(1);

with

LinkedList<Integer> list = new LinkedList<Integer>(1);

or just any other version by incorporating the compatible changes.


Collections and Primitive Values

Collections in Java only work for objects. I.e. there is no Map<int, int> in Java. Instead, primitive values need to be boxed into objects, as in Map<Integer, Integer>. Java auto-boxing will enable transparent use of these collections:

Map<Integer, Integer> map = new HashMap<>();
map.put(1, 17); // Automatic boxing of int to Integer objects
int a = map.get(1); // Automatic unboxing.

Unfortunately, the overhead of this is substantial. A HashMap<Integer, Integer> will require about 72 bytes per entry (e.g. on 64-bit JVM with compressed pointers, and assuming integers larger than 256, and assuming 50% load of the map). Because the actual data is only 8 bytes, this yields a massive overhead. Furthermore, it requires two level of indirection (Map -> Entry -> Value) it is unnecessarily slow.

There exist several libraries with optimized collections for primitive data types (that require only ~16 bytes per entry at 50% load, i.e. 4x less memory, and one level of indirection less), that can yield substantial performance benefits when using large collections of primitive values in Java.

Basic Programs