I am coding some validators for a REST service which parse a JSON and I found out something that sounds wierd for me (I am not a JAVA expert at all).
Consider having two ArrayLists:
ArrayList<Object> list1 = new ArrayList<Object>();
ArrayList<Object> list2 = new ArrayList<Object>();
Both lists have something in common: they are completely empty (or full of null elements). But if I do:
list1.add(null);
Although both remain completely empty, they have completely different behaviors. And to make some methods the results are very different:
System.out.println(list1.contains(null)); //prints true!
System.out.println(list2.contains(null)); //prints false
System.out.println(CollectionUtils.isNotEmpty(list1)); //prints true
System.out.println(CollectionUtils.isNotEmpty(list2)); //prints false
System.out.println(list1.size()); //prints 1
System.out.println(list2.size()); //prints 0
Doing some research, and looking at the implementation of each of these methods, you can determine the reason for these differences, but still do not understand why it would be valid or useful to differentiate between these lists.
- Why add(item) doesnt validate if item!=null ?
- Why contains(null) says false if the list is full of nulls?
Thanks in advance!!!
EDIT:
I am mostly agree whit the answers, but I'm not yet convinced all. This is the implementation of the method remove:
/**
* Removes the first occurrence of the specified element from this list,
* if it is present. If the list does not contain the element, it is
* unchanged. More formally, removes the element with the lowest index
* <tt>i</tt> such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>
* (if such an element exists). Returns <tt>true</tt> if this list
* contained the specified element (or equivalently, if this list
* changed as a result of the call).
*
* @param o element to be removed from this list, if present
* @return <tt>true</tt> if this list contained the specified element
*/
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
/*
* Private remove method that skips bounds checking and does not
* return the value removed.
*/
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
So, now if i do:
ArrayList<Object> list = new ArrayList<Object>();
list.add(null);
System.out.println(list.contains(null)); //prints true!
list.remove(null);
System.out.println(list.contains(null)); //prints false!
what I'm missing?