Difference between an empty ArrayList and an ArrayList with null elements?

27,936

Solution 1

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.

Solution 2

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.

Solution 3

Fortunately you don't have to be a java expert or an expert at all.

The best way to think of this is like a parking lot. An array with null elements is like a parking lot with nothing parked in it. An empty array is like the plans for a parking lot.

Share:
27,936
melli-182
Author by

melli-182

Enjoy programming (specially java and webApps). Loves rowing.

Updated on July 09, 2022

Comments

  • melli-182
    melli-182 almost 2 years

    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&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;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?

  • melli-182
    melli-182 over 8 years
    Ok! Thats right, i agree with you. But, whats the difference between list 1 and 2?
  • Pshemo
    Pshemo over 8 years
    "Lists are allowed to contain null" can be misleading since there is no guarantee that all list do so. But it is true in case of ArrayList.
  • dsh
    dsh over 8 years
    @melli-182 The difference is one is empty, and one has something (a null) in it. Write a loop to print out the elements and you'll see that one executes the loop body zero times with no output and one executes one time with one line of output. One of them will throw an ArrayIndexOutOfBounds exception if you try to .get(0) and the other will return to you the null value that is at index 0.