I have created a custom linked list that implements the Iterable
interface. I am then using this linked list to implement my custom stack. I have also thrown a custom exception while removing elements.
LinkedList
class:
package collections.customCollections.linkedList; import java.util.Iterator; public class LinkedList<T> implements Iterable<T>{ private Link<T> head; private Link<T> tail; private int size; public int getSize() { return size; } public LinkedList(){ head = null; tail = null; size=0; } public void addAtEnd(T data){ Link<T> newNode = new Link<T>(data); //Insert as first element if(head == null){ head = newNode; tail = newNode; } else{ newNode.previous = tail; tail.next = newNode; tail = newNode; } size++; } public void addAtStart(T data){ Link<T> newNode = new Link<T>(data); if(head == null){ head = newNode; tail = newNode; } else{ newNode.next = head; head.previous = newNode; head = newNode; } size++; } //prints the entire linked list public void print(){ Link<T> traversalNode = head; if(head == null){ System.out.println("Empty Linked List"); } else{ while(traversalNode != null){ System.out.print(traversalNode.data +"->"); traversalNode = traversalNode.next; } } } public T remove(int index){ int i = 1; Link<T> traversalNode = head; while(i < index){ traversalNode = traversalNode.next; i++; } if(traversalNode.next == null){ removefromEnd(); } else if(traversalNode.previous == null){ removeFromStart(); } else{ traversalNode.previous.next = traversalNode.next; traversalNode.next.previous = traversalNode.previous; traversalNode.next = null; traversalNode.previous = null; } return traversalNode.data; } public T removefromEnd(){ Link<T> nodeToRemove = tail; tail = nodeToRemove.previous; tail.next = null; size--; return nodeToRemove.data; } public T removeFromStart(){ Link<T> nodeToRemove = head; head = nodeToRemove.next; head.previous = null; size--; return nodeToRemove.data; } public T get(int index) { Link<T> returnedNode = head; int i = 1; while(i < index){ returnedNode = returnedNode.next; i++; } return returnedNode.data; } private class Link<T>{ private T data; private Link<T> next = null; private Link<T> previous = null; public Link(T data){ this.data = data; } } @Override public Iterator<T> iterator() { return new Iterator<T>(){ private int position = 1; @Override public boolean hasNext() { if(position <= getSize()){ return true; } return false; } @Override public T next() { T data = get(position); position++; return data; } @Override public void remove() { LinkedList.this.remove(position); } }; } }
The Stack
class:
package collections.cutomcollections.stack; import collections.customCollections.exceptions.UnderFlowException; import collections.customCollections.linkedList.LinkedList; public class Stack<T> { private LinkedList<T> list; public Stack(){ list = new LinkedList<>(); } public int getSize() { return list.getSize(); } public void push(T data){ list.addAtEnd(data); } public T pop(){ if(list.getSize() <= 0){ throw new UnderFlowException("Empty Stack.No Elements in the Stack to pop."); } return list.removefromEnd(); } public T peek(){ if(list.getSize() <= 0){ throw new UnderFlowException("Empty Stack.No Elements in the Stack to pop."); } return list.get(list.getSize()-1); } }
The Exception
class:
package collections.customCollections.exceptions; public class UnderFlowException extends RuntimeException{ public UnderFlowException(String message){ super(message); } public UnderFlowException(String message,Throwable cause){ super(message,cause); } }
I tried to incorporate all the comments I received from my previous questions into this code. What all are the further improvements I can make?
I also have some questions. I had to use LinkedList.this.remove(position)
inside the remove method of the anonymous iterator class while I could simply call removeFromEnd()
. The answer I got for this was that the compiler cannot differentiate due to the same name (even though they have different number of arguments) since the anonymous class is still a completely different class. Does that mean if I have a class that implements two different interfaces have methods that have same name but different arguments, I'll get the same error?
Another question is regarding the Link
class inside the LinkedList
class. I get a warning saying "The type parameter T is hiding the type T" where I declare the private
class Link
. I searched about it but couldn't understand the answers I found.
Then the custom exception that I created is an unchecked exception since I don't want users to explicitly handle it when they use my stack or list. But I am throwing this exception in my stack impl. If another class uses my linked list they would get a null pointer exception if say they invoked the remove method on an empty list. Should I do it at the list level?