0

I am trying to create class that extends the java.util.ArrayList by overriding the add method in the following way: it does nothing if the object to be added already exists in the collection; otherwise it calls the add method in the super class to add the object into the collection.

My code look like that so far but it gives a NullPointerException:

import java.util.ArrayList;

public class myArrayList<E> extends ArrayList<E> {
    public ArrayList<E> mylist;

    @Override
    public boolean add(E e) {
        if (!mylist.contains(e)) {
            super.add(e);
            return true;
        } else {
            return false;
        }
    }
}

    public static void main(String[] args) {
        myArrayList<Integer> listing = new myArrayList<Integer>();
        listing.add(4);
        listing.add(4);
        for (int i = 0; i < listing.size(); i++) {
            System.out.println(listing.get(i));
        }
    }
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216

2 Answers2

2

While we can't be sure this is your problem (unless you show us the stacktrace!), it looks like an NPE is likely to occur in this line:

    if (!mylist.contains(e)) {

because mylist is never initialized.

In fact, if you are trying to extend ArrayList rather than create a list wrapper, the mylist variable should not exist at all. The list state is in the superclasses private variables. Instead, the add method should probably be written like this:

@Override
public boolean add(E e) {
    if (!super.contains(e)) {
        return super.add(e);  // See note
    } else {
        return false;
    }
}

Note: in general, you should return whatever the superclass returns here. However, when the superclass is ArrayList, we know1 that add will return true, so this is only "saving" a line of code. There might be marginal performance difference, depending on how smart the JIT optimizer is.

1 - We know because the ArrayList.add javadoc specifically states that true is returned.


But this looks like you are trying to create a "set-like" list class. There could be better alternatives; e.g. LinkedHashSet has a defined iteration order, and addition is O(1) rather than O(N). (Admittedly, LinkedHashSet uses a lot more memory, and it has no efficient equivalent to the positional List.get(int) method.)

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

You got a NullPointerException on this line if (!mylist.contains(e)) { because myList is not instanciated in the default constructor.

public MyArrayList() {
 this.myList = new ArrayList<>();
}

But.. you mix inheritance and composition here...

That means add will be applied to myList and get(index) will be applied on this.. So you actually maintain 2 lists here..

In you example myList.contains will always return false because you never add something into. this -> super.add(e) is the same than this.add(e) and it is a different instance of list.

So just removed myList instance field and replace your add like this :

  @Override
    public boolean add(E e) {
        if (!contains(e)) {
            add(e);
            return true;
        } else {
            return false;
        }
    }

Watch out that this class is not thread-safe. Here there is a check-then-act race condition (check = contains(), act = add())

Finally List are designed to allow duplicates... if you don't want duplicates.. just use a Set

CodeScale
  • 3,046
  • 1
  • 12
  • 20