33

I have Book and BookList classes. BookList is something like this:

public class BookList 
{
    private final List<Book> bList = new ArrayList<Book>();

    public int size() { return bList.size(); }

    public boolean isEmpty() {  ... }

    public boolean contains(Book b) { ...  }

    public boolean add(Book b) { ...  }

    public boolean remove(Book b) {  .. } 

    public void clear() { ... }

    public Book get(int index) { ... }
 
}

In my main class I want to print titles of books with in a for each loop:

for(Book b : bList)
{
    b.print();
}

Eclipse says:

Can only iterate over an array or an instance of java.lang.Iterable

How can I get this working?

b4da
  • 3,010
  • 4
  • 27
  • 34

5 Answers5

40

You need to implement the Iterable interface, which means you need to implement the iterator() method. In your case, this might look something like this:

public class BookList implements Iterable<Book> {
    private final List<Book> bList = new ArrayList<Book>();

    @Override
    public Iterator<Book> iterator() {
        return bList.iterator();
    }

    ...
}
andersschuller
  • 13,509
  • 2
  • 42
  • 33
35

Implement the Iterable interface. That means you need to implement a method that returns an Iterator object that will iterate over the elements of a BookList.

In this case, your iterator() method could just return the result of calling bList.iterator(). (That will cause for (Book b : somBookList) to iterate over the Book objects in the BookList.bList ... )

In other cases, you might need to write your own Iterator<T> implementation class, complete with T next(), boolean hasNext() and remove() methods. For instance, if you wanted to prevent external code from removing elements from the BookList via your iterator, you might implement it like this:

public class BookList implements Iterable<Book> {
    private final List<Book> bList = new ArrayList<Book>();
    //...
    @Override
    public Iterator<Book> iterator() {
        return new Iterator<Book> () {
            private final Iterator<Book> iter = bList.iterator();

            @Override
            public boolean hasNext() {
                return iter.hasNext();
            }

            @Override
            public Book next() {
                return iter.next();
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException("no changes allowed");
            }
        };
    }
}
Nateowami
  • 1,005
  • 16
  • 23
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
10

Here we can see the simple implementation of LinkedList with iterator and foreach syntax

class LinkedList implements Iterable<LinkedList.Node>{
    private Node node;
    public void add(Object data){
        if(!Optional.ofNullable(node).isPresent()){
            node = new Node();
            node.setData(data);
        }else{
            Node node = new Node();
            node.setData(data);
            Node lastNode = getLastNode(this.node);
            lastNode.setNext(node);
        }
    }

    private Node getLastNode(Node node){
        if(node.getNext()==null){
            return node;
        }else{
            return getLastNode(node.getNext());
        }
    } 

    class Node{
        private Object data;
        private Node next;
        public Object getData() {
            return data;
        }
        public void setData(Object data) {
            this.data = data;
        }
        public Node getNext() {
            return next;
        }
        public void setNext(Node next) {
            this.next = next;
        }
    }

    public Iterator<Node> iterator() {
        return new NodeIterator();
    }

    class NodeIterator implements Iterator<Node>{
        private Node current;

        public boolean hasNext() {
            if(current == null){
                current = node;
                return Optional.ofNullable(current).isPresent();
            }else{
                current = current.next;
                return Optional.ofNullable(current).isPresent();
            }
        }

        public Node next() {
            return current;
        }
    }
}

public class LinkedListImpl {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.add("data1");
        linkedList.add("data2");
        linkedList.add("data3");
        for(LinkedList.Node node: linkedList){
            System.out.println(node.getData());
        }
    }
}
Pang
  • 9,564
  • 146
  • 81
  • 122
user3531588
  • 114
  • 1
  • 4
3

To be more specific about how to "implement the Iterable interface":

public class BookList implements Iterable<Book>
{
    private final List<Book> bList = new ArrayList<Book>();

    ... 

    @Override
    public Iterator<Book> iterator()
    {
        return bList.iterator();
    }
}
Alden
  • 6,553
  • 2
  • 36
  • 50
  • 4
    Note that this will allow callers to remove books without going through the BookList.remove() method, which breaks encapsulation. You'd better use `return Collections.unmodifiableList(bList).iterator();` – JB Nizet Feb 02 '14 at 15:29
1

For making a class iteratable you need to implement Iterable Interface.

a) Declare the class as below

public class BookList implements Iterable<Book>

b) Override the iterator() Method

Read More. Hope it will help you.

JDGuide
  • 6,239
  • 12
  • 46
  • 64