Implementing contains, add, and remove
All three operations reject null first, then do their work by traversing the list.
The contains operation is a linear search: traverse from the head, comparing each value with the item using equals.
@Override
public boolean contains(T item) {
if (item == null) {
throw new IllegalArgumentException();
}
Node<T> curr = head;
while (curr != null) {
if (item.equals(curr.value)) {
return true;
}
curr = curr.next;
}
return false;
}
The add operation must not create a duplicate, so it checks for the item first. If the item is already present, it changes nothing and returns false. Otherwise it links a new node in at the head, because that is the cheapest place to insert, and updates the size.
@Override
public boolean add(T item) {
if (item == null) {
throw new IllegalArgumentException();
}
if (contains(item)) {
return false; // already present; a set holds no duplicates
}
Node<T> newNode = new Node<>(item);
newNode.next = head; // insert at the head
head = newNode;
size++;
return true;
}
The remove operation searches for the item, but it has to remember the node before the target so it can skip over it by linking the “before target” node to one after it.
@Override
public boolean remove(T item) {
if (item == null) {
throw new IllegalArgumentException();
}
Node<T> prev = null;
Node<T> curr = head;
while (curr != null) {
if (item.equals(curr.value)) {
if (prev != null) {
prev.next = curr.next;
} else {
head = head.next;
}
size--;
return true;
}
prev = curr;
curr = curr.next;
}
return false;
}