MyLinkedList.java

package ch.hslu.exercises.sw02.ex2;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import java.util.AbstractList;
import java.util.Iterator;

public final class MyLinkedList<T> extends AbstractList<T> {

    private Node<T> head = null;

    @Override
    public boolean isEmpty() {
        return head == null;
    }

    @SafeVarargs
    public final void insertAtHead(final T... elements) {
        for (T element : elements) {
            insertAtHead(element);
        }
    }

    private void insertAtHead(final T element) {
        Node<T> newNode = new Node<>(element);
        newNode.setNext(head);
        head = newNode;
    }

    public T popElementAtHead() {
        if (isEmpty()) {
            throw new IllegalStateException("No head element on empty list.");
        } else {
            Node<T> oldHead = head;
            removeHead();
            return oldHead.getValue();
        }
    }


    private void removeHead() {
        head = head.getNext();
    }

    @Override
    public int size() {
        int i = 0;
        for (T ignored : this) {
            i++;
        }
        return i;
    }


    public T getHead() {
        if (isEmpty()) {
            throw new IllegalStateException("No head element on empty list.");
        } else {
            return head.getValue();
        }
    }

    public void removeElement(final T elementToBeRemoved) {
        if (head.getValue().equals(elementToBeRemoved)) {
            removeHead();
            return;
        }
        Node<T> temp = head, prev = null;
        while (temp != null && temp.getValue() != elementToBeRemoved) {
            prev = temp;
            temp = temp.getNext();
        }
        if (temp == null) {
            return;
        }
        prev.setNext(temp.getNext());
    }


    @Override
    public T get(final int index) {
        if (isEmpty()) {
            throw new IllegalStateException("The List is empty");
        }
        int i = 0;
        for (T element : this) {
            if (i == index) {
                return element;
            }
            i++;
        }
        return null;
    }

    @NotNull
    @Contract(" -> new")
    @Override
    public Iterator<T> iterator() {
        return new MyLinkedListIterator();
    }


    private final class MyLinkedListIterator implements Iterator<T> {
        private Node<T> current = head;

        @Override
        public boolean hasNext() {
            return current != null;
        }

        @Override
        public T next() {
            T data = current.getValue();
            current = current.getNext();
            return data;
        }

    }

    private static final class Node<E> {
        private final E value;
        private Node<E> next;

        Node(final E value) {
            this.value = value;
        }

        public E getValue() {
            return this.value;
        }

        public Node<E> getNext() {
            return this.next;
        }

        public void setNext(final Node<E> next) {
            this.next = next;
        }
    }
}