起初,我将null插入树上.之后,我插入了任何其他价值,为什么它会给NPE


 public static void main(String []args){
    TreeSet tree = new TreeSet();
    String obj = "Ranga";
    tree.add(null);
    tree.add(obj);
 }

据我所知,树木取决于默认的自然分类顺序。因此,JVM内部调用CompareTo((方法。

在上面的示例中,情况是:

obj.compareto(null(;

so,为什么结果为null指针异常?

从1.7开始,null根本不接受null。如果您执行添加,那么我们将获得NullPoInterException。直到1.6 NULL仅作为第一个元素接受。

Java 7-

之前

对于非空树,如果我们试图在运行时插入空值,则将获得NullPoInterException。这是因为当树中存在某些元素时,在插入任何对象之前,它将新对象与现有对象进行比较的对象,并决定将新对象放置在何处。因此,通过插入null CompareTo((方法内部抛出NullPoInterException。

treemap添加方法文档

当您尝试在空树上添加null时,它最初不包含任何元素可以比较它,因此没有NPE,当您将第二个元素添加到树中时,TreeT将使用可比较的compareTo((方法来对元素进行排序并放置因此,它将称为Null.comPareto((,该null.compareto((挑衅地通向NPE。

在内部由Treemap备份的TREETET在Java 7 Treemap put(K,V(之前没有null检查K(key(,并且在treemap put(k.v(mehod

中添加了java 7 null检查。

Java 7 Treemap放置MeHod代码没有空检查 -

  public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {
            incrementSize();
            root = new Entry<K,V>(key, value, null);
            return null;
       }
        while (true) {
            int cmp = compare(key, t.key);
            if (cmp == 0) {
                return t.setValue(value);
            } else if (cmp < 0) {
                if (t.left != null) {
                    t = t.left;
                } else {
                    incrementSize();
                    t.left = new Entry<K,V>(key, value, t);
                    fixAfterInsertion(t.left);
                    return null;
                }
            } else { // cmp > 0
                if (t.right != null) {
                    t = t.right;
                } else {
                    incrementSize();
                    t.right = new Entry<K,V>(key, value, t);
                    fixAfterInsertion(t.right);
                    return null;
                }
            }
        }
    }

从java 7中,您可以看到null检查键的null检查,如果它为空,它将抛出npe。

public V put(K key, V value) {
    Entry<K,V> t = root;
    if (t == null) {
        compare(key, key); // type (and possibly null) check
        root = new Entry<>(key, value, null);
        size = 1;
        modCount++;
        return null;
    }
    int cmp;
    Entry<K,V> parent;
    // split comparator and comparable paths
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        do {
            parent = t;
            cmp = cpr.compare(key, t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    else {
        if (key == null)
            throw new NullPointerException();
        Comparable<? super K> k = (Comparable<? super K>) key;
        do {
            parent = t;
            cmp = k.compareTo(t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    Entry<K,V> e = new Entry<>(key, value, parent);
    if (cmp < 0)
        parent.left = e;
    else
        parent.right = e;
    fixAfterInsertion(e);
    size++;
    modCount++;
    return null;
}

我希望这能带领您得出适当的结论。

只是为了维持合同,而自然有序的可比较的incase则执行了行为。

C级的自然排序与e1.compareto(e2(== 0的自然顺序与平等相一致。

在"相对较新的" java版本中(来自第六版(, NullPointerException有望在第一个add()调用中抛出:

tree.add(null);

作为TreeSet.add() Javadoc说:

投掷NullPoInterException - 如果指定的元素为null,并且该集合使用自然排序,则 或其比较器不允许null元素

请注意,它是从JDK 6以这种方式指定的。
例如,JDK 5并未明确说明这一点。

如果您使用旧的Java版本(如Java 5(,请指定。

首先,不要使用原始类型,而是利用仿制药的力量:

TreeSet<String> tree = new TreeSet<>();

至于您的问题:

TreeSet不再支持添加null

来自文档:

public boolean add(E e)

如果指定的元素为null,则抛出NullPointerException 使用自然订购或其比较器不允许null 元素。

解决此问题的解决方案:

提供一个无效的比较器,其中null元素将首先出现:

TreeSet<String> tree = new TreeSet<>(Comparator.nullsFirst(Comparator.naturalOrder()));

或提供无效的比较器,其中null元素将持续:

TreeSet<String> tree = new TreeSet<>(Comparator.nullsLast(Comparator.naturalOrder()));

最新更新