Search code examples
javaarraylistimplementationlistiterator

How to implement ListIterator?


I created this extension of ArrayList, NullIgnoringArrayList, because it's possible that my application will add nulls from time to time. I know there are various other ways to deal with this, like checking for null before inserting or filtering out nulls when accessing the ArrayList. But I got it in my head to do it this way and it was going fine but now I don't know how to proceed.

I should implement ListIterator because my tests call upon this method. I peaked in the implementation inside ArrayList but there ListItr is a private class that uses the private fields of ArrayList, which I don't have in NullIgnoringArrayList.

To be fair though, I might be overengineering and maybe I should just drop it. On the other hand, one might learn a thing or two.

NullIgnoringArrayList:

public class NullIgnoringArrayList<T> extends ArrayList<T> {

    @Override
    public boolean add(T element) {
        return !isNull(element) && super.add(element);
    }

    @Override
    public void add(int index, T element) {
        if (isNull(element)) {
            return;
        }
        super.add(index, element);
    }

    @Override
    public boolean addAll(Collection c) {
        return !isNull(c) && super.addAll(c);
    }

    @Override
    public boolean addAll(int index, Collection c) {
        return !isNull(c) && super.addAll(index, c);
    }

    @Override
    public ListIterator listIterator() {
        throw new NotImplementedException();
    }

    @Override
    public ListIterator listIterator(int index) {
        throw new NotImplementedException();
    }
}

SimpleListIterator:

public class SimpleListIterator<T> implements ListIterator {
    @Override
    public boolean hasNext() {
        return false;
    }

    @Override
    public Object next() {
        return null;
    }

    @Override
    public boolean hasPrevious() {
        return false;
    }

    @Override
    public Object previous() {
        return null;
    }

    @Override
    public int nextIndex() {
        return 0;
    }

    @Override
    public int previousIndex() {
        return 0;
    }

    @Override
    public void remove() {

    }

    @Override
    public void set(Object o) {

    }

    @Override
    public void add(Object o) {

    }
}

Solution

  • Just delegate method calls to ListIterator<T> of the parent:

    public class NullIgnoringArrayList<T> extends ArrayList<T> {
    
        ...
    
        @Override
        public ListIterator<T> listIterator() {
            return new SimpleListIterator<>(super.listIterator());
        }
    
        @Override
        public ListIterator<T> listIterator(int index) {
            return new SimpleListIterator<>(super.listIterator(index));
        }
    }
    
    public class SimpleListIterator<T> implements ListIterator<T> {
    
        private final ListIterator<T> underlying;
    
        public SimpleListIterator(ListIterator<T> underlying) {
            this.underlying = underlying;
        }
    
        @Override public boolean hasNext() {return underlying.hasNext();}
        @Override public T next() { return underlying.next(); }
        @Override public boolean hasPrevious() {return underlying.hasPrevious();}
        @Override public T previous() {return underlying.previous();}
        @Override public int nextIndex() {return underlying.nextIndex();}
        @Override public int previousIndex() {return underlying.previousIndex();}
        @Override public void remove() { underlying.remove();}
    
        @Override
        public void set(T o) {
            if (isNull(o)) {return;}
            underlying.set(o);
        }
    
        @Override
        public void add(T o) {
            if (isNull(o)) {return;}
            underlying.add(o);
        }
    }