1

for uni we are supposed to implement an iterator for a String linked list by ourselves. But the infos how to do that was pretty small. So we tried it by ourselves and googled a lot but all the explanations we found dont include the whole code and I dont get how to implement the iterator correct. I think everything works fine as long as we use the for each loop to use the iterator but as soon as we are trying to use the "while (iterator.hasnext) { next }" thing it stays in the first element of the linked list. I think I know this problem is based on that we are always instantiating a new iterator but I dont get how to implement it else. Hopefully someone can help, I really don't know what to do, I tried everything..

import java.util.Iterator;
import java.util.NoSuchElementException;

public class LinkedList implements Iterable<String> {

     // ---------- Attributes ---------- 

     private int size = 0;
     private Node head = null;
     // private Iterator<String> linkedListIterator = this.iterator(); // ??

     static class Node {
    
        // ---------- Attributes ---------- 
    
        private String object;
        private Node next;
    
        // ---------- Constructors ---------- 
    
        public Node(String object, Node node) {
             this.object = object; 
             this.next = node;
        }
    
        public Node() { 
            this(null, null); 
        }
    
        // ---------- Getter, Setter ---------- 
    
        public String getElement() { 
            return this.object; 
        }
    
        public void setElement(String object) { 
            this.object = object; 
        }
    
        public Node getNext() { 
            return this.next; 
        }
    
        public void setNext(Node node) { 
            this.next = node; 
        }
    }

    class LinkedListIterator implements Iterator<String> {

        // ---------- Attributes ---------- 

        private Node currentNode = null;
        private int counter = 0;

        // ---------- Constructor ---------- 

        public LinkedListIterator(LinkedList linkedList) {
            this.currentNode = linkedList.head;
        }

        // ---------- Getter, Setter, Methods ---------- 

        public boolean hasNext() {
            return this.currentNode != null;
        }

        public String next() {
            if (!this.hasNext()) {
                System.out.println("Fehler: ");
                throw new NoSuchElementException();
            }

            String object = this.currentNode.getElement(); // ?
            this.currentNode = this.currentNode.getNext();
            this.counter++;
        
            return object;
        }
    
        public int getCounter() {
            return this.counter;
        }

    }

    // ---------- Getter, Setter, Methods ---------- 

    public Node getHead() {
        return this.head;
    }

    public void addFirst(String object) {
        // new node as head
        Node newNode = new Node(object, this.head);
        this.head = newNode;    
        this.size++;
    }

    public String getFirst() { //throws ListEmptyException {
        if (isEmpty()) {
            //      throw new ListEmptyException();
        }
        return this.head.getElement();
    }

    public String removeFirst() { //throws ListEmptyException {
        if (isEmpty()) {
            //      throw new ListEmptyException();
        }

        String object = this.head.getElement();
        this.head = this.head.getNext();
        return object;
    }

    public boolean isEmpty() {
        return this.head == null;
    }

    public int getSize() {
        return this.size;
    }

    @Override
    public Iterator<String> iterator() {
        System.out.println("helo");
        return new LinkedListIterator(this);
    }

    public String toString() {
        String output = "";

    //      this is working:
    //      for (String element: this) {
    //          output += element + "\n";
    //      }
    
        while (this.iterator().hasNext()) {
            System.out.println(this.iterator().hasNext());
            output += this.iterator().next() + "\n";
        }
    
        return output;
    }

    public static void main(String[] args) {
        LinkedList ll = new LinkedList();
        ll.addFirst("a");
        ll.addFirst("b");
        ll.addFirst("c");
        ll.addFirst("d");
        ll.addFirst("e");       
    
        System.out.println(ll.toString());
    }

}

Problem solved by this

But new question: Why is this working

public String toString() {
    String output = "";
    Iterator<String> iterator = this.iterator();

    while (iterator.hasNext()) {
        output += it.next() + "\n";
    }
    return output;
}

But this not

public class LinkedList implements Iterable<String> {

    private Iterator<String> linkedListIterator = this.iterator();

    public String toString() {
        String output = "";
    
        while (this.linkedListIterator.hasNext()) {
            output += this.linkedListIterator.next() + "\n";
        }
        return output;
    }
}

1 Answer 1

1

Your implementation of LinkedListIterator is correct, the problem is in the toString() method. You are calling this.iterator() 3 times, so each time you return a new instance of LinkedListIterator. Instead you have to call this.interator() only once and use the instance you get. Like this:

    Iterator<String> it=this.iterator();
    while (it.hasNext()) {
    System.out.println(it.hasNext());
    output += it.next() + "\n";
    }

Regarding the new question.
If you instantiate the private Iterator<String> linkedListIterator attribute in the body of the class, (Something that should never be done), every time you refer to it you will make a call to the public Iterator<String> iterator() method and you will get a new instance of LinkedListIterator.
You are making the same mistake as in the beginning. This is an example of why attributes should be instantiated only within a method declaration.
Remember that an iterator can only move forward, if you want to restart it you must create a new instance. That's what you do by calling this.iterator().
I recommend you to use some debugging tools so you can see the instructions that are executed
Also, there is a design pattern that deals iterators. https://en.wikipedia.org/wiki/Iterator_pattern

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks now it's working! :) I now wrote the "Iterator<String> it = this.iterator();" directly into the toString() method. But what I still don't understand is why is it only working when I write it directly into the toString(). When I write it as general attribute in the LinkedList class it is not working. Why?
I don't understand, what do you mean with: "I write it as general attribute in the LinkedList class" ?
I dont know how to add a code block to the comments, so I added my question to the code on the top (the new two code blocks)
I edited my previous answer, I hope you understand now
Ahh ok, didnt know that. Thanks for your help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.