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.
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?
No. An ArrayList can be empty (or with nulls as items) an not be null. It would be considered empty.
An empty collection is actually a collection, but there aren't any elements in it yet. null means no collection exists at all.
In ArrayList, any number of null elements can be stored. While in HashMap, only one null key is allowed, but the values can be of any number.
v == null : o. equals(v) ). i.e. if o is null , it returns true only if one element is null in the ArrayList. If o is not null , it returns true only if at least one element equal to v.
A list containing null
is NOT empty. It contains null
. Lists are allowed to contain null, so you can put null in it if you want.
An ArrayList
explicitly is allowed and able to store null
values, because they might be meaningful to your program. And empty list is empty (i.e. doesn't contain anything, not even null
. After you successfully add(null) (it returns true
to signal success), the list must obviously return true
on contains(null) as well. In fact, you can even remove(null) from that list and it will be empty again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With