在写代码的时候,有时候遇到for循环,写到下面的时候有一点犹豫。

List<Data> dataList = ...;
for (Data d : dataList) {
    if (d != null) { // 需要这个判断吗?
        // ...
    }
}

产生上述疑问,究其原因在于对List源码不熟悉,虽然知道List接口有LinkedList(基于链表实现)、ArrayList(基于数组实现)等实现类,但其执行add方法的细节没关注,就会产生如题的疑惑。本文先得出结论,最后再去分析其中的原因。

在本地写test代码,往List中add null对象,然后再做遍历。

private void printList() {
    List<Integer> dataList = new ArrayList<>();
    dataList.add(1);
    dataList.add(null);
    dataList.add(null);

    for (Integer d : dataList) {
        System.out.println(d);
    }

    System.out.println("------------------------");

    for (Integer d : dataList) {
        if (d != null) { // 需要这个判断吗?
            System.out.println(d);
        }
    }
}

测试函数输出

1
null
null
------------------------
1

针对问题:List可以add(null)吗?答案是肯定的,null对象是可以添加到列表中。这一点通过上述例子也很好理解。

理解此问题的关键点在于ArrayList底层的原理,针对本问题重点在于:

  • List底层是数组即,Object[] elementData,数组对元素没限制。这一点可以通过源码解释:
/**
 * This helper method split out from add(E) to keep method
 * bytecode size under 35 (the -XX:MaxInlineSize default value),
 * which helps when add(E) is called in a C1-compiled loop.
 */
private void add(E e, Object[] elementData, int s) {
    if (s == elementData.length)
        elementData = grow();
    elementData[s] = e;
    size = s + 1;
}

/**
 * Appends the specified element to the end of this list.
 *
 * @param e element to be appended to this list
 * @return {@code true} (as specified by {@link Collection#add})
 */
public boolean add(E e) {
    modCount++;
    add(e, elementData, size);
    return true;
}
  • 关于Java对象是否能处理null,不要与Hashmap和Hashtable混淆,HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行。这一点通过源码解释:

Hashmap底层是由数组、链表、红黑色组成。数组的下标通过key值决定,

Node<K,V>[] table;
// key为null时,哈希值为0
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
// 数组下标计算方式
tab[i = (n - 1) & hash

Hashtable底层是由数组、链表组成。数组的下标通过key值决定,

public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
    throw new NullPointerException();
}

// key为null的话,key.hashCode()就会报NullPointerException
// Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> entry = (Entry<K,V>)tab[index];
for(; entry != null ; entry = entry.next) {
    if ((entry.hash == hash) && entry.key.equals(key)) {
        V old = entry.value;
        entry.value = value;
        return old;
    }
}

addEntry(hash, key, value, index);
return null;
}