这些集允许null。为什么我不能添加null元素?

时间:2013-02-08 14:27:36

标签: java null hashset

我想知道为什么HashSet,LinkedHashSet和TreeSet实现不允许null元素? 每当我尝试运行以下代码时,它都会抛出一个空指针异常。

public static void main(String[] args) {

    HashSet<Integer> hashSet = new HashSet<Integer>();

    hashSet.add(2);
    hashSet.add(5);
    hashSet.add(1);
//  hashSet.add(null);  will throw null pointer 
    hashSet.add(999);
    hashSet.add(10);
    hashSet.add(10);
    hashSet.add(11);
    hashSet.add(9);
    hashSet.add(10);
    hashSet.add(000);
    hashSet.add(999);
    hashSet.add(0);

    Iterator<Integer> it = hashSet.iterator();
    while(it.hasNext()){
        int i = it.next();
        System.out.print(i+" ");
    }
    }

请指导我。

10 个答案:

答案 0 :(得分:54)

这就是为什么我不喜欢依靠自动拳击。 Java Collections无法存储原语(为此您需要第三方API,如Trove)。所以,实际上,当你执行这样的代码时:

hashSet.add(2);
hashSet.add(5);

真正发生的事情是:

hashSet.add(new Integer(2));
hashSet.add(new Integer(5));

在哈希集中添加null是 问题,该部分工作得很好。当您尝试将值拆分为原始int时,您的NPE会出现:

while(it.hasNext()){
    int i = it.next();
    System.out.print(i+" ");
}

当遇到null值时,JVM会尝试将其拆分为int原语,从而导致NPE。您应该更改代码以避免这种情况:

while(it.hasNext()){
    final Integer i = it.next();
    System.out.print(i+" ");
}

答案 1 :(得分:21)

1)你确定你得到编译时间错误吗?我不这么认为,我想代码在运行时抛出NPE

int i = it.next();

2)事实上java.util.Set接口不禁止null元素,并且一些JCF Set实现也允许null元素:

设置API - A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element.

HashSet API - This class permits the null element

LinkedHashSet API - This class provides all of the optional Set operations, and permits null elements

TreeSet.add API - throws NullPointerException - if the specified element is null and this set uses natural ordering, or its comparator does not permit null elements

答案 2 :(得分:6)

不,设置接口允许空值仅限其实现,即TreeSet不允许空值。

即使您没有编写迭代代码并且代码中只有oTreeSet.add(null),它也会在运行时抛出NullPointerException。

TreeSet类的add()方法在内部调用TreeMap类的put()方法。 {(1}}值不允许使用put()方法

中的以下代码
null

答案 3 :(得分:4)

Set接口的要点是使用有关元素(哈希码或比较)的信息来加快实现。

null没有这些信息。

答案 4 :(得分:4)

Set Interface不允许为null,因为在TreeSet中,它以排序顺序存储元素,所以每次添加新元素时它会比较值然后进行排序。所以内部发生的事情是它将新添加的空值与现有值进行比较,因此它将抛出NullPointerException。

String str=null;
if(str.equals("abc"))
{
}
//it will throw null pointer exception

这就是为什么它不允许空值。

答案 5 :(得分:1)

您提到过:

<块引用>

// hashSet.add(null);会抛出空指针

这是不正确的,因为 HashSet 确实允许向其中添加 null,因此,您不会遇到此语句的任何编译失败或运行时异常。但是,当下面的语句将被执行时

int i = it.next();

您将收到如下所示的运行时异常:

<块引用>

线程“main”中的异常java.lang.NullPointerException:不能 调用“java.lang.Integer.intValue()”因为返回值 "java.util.Iterator.next()" 在 Main.main(Main.java:24) 处为空

例外是不言自明的。 JLS §5.1.8 指定如下:

<块引用>

如果 r 为 null,拆箱转换会抛出 NullPointerException

下面给出了另一个理解这个概念的例子:

public class Main {
    public static void main(String[] args) {
        Integer x = null;
        print(x);
    }

    static void print(int x) {
        System.out.println(x);
    }
}

输出:

<块引用>

线程“main”中的异常java.lang.NullPointerException:不能 调用“java.lang.Integer.intValue()”因为“x”在 Main.main(Main.java:7)

事实上,编译器会提前警告你:

<块引用>

空指针访问:这个Integer类型的表达式为空但是 需要自动拆箱

答案 6 :(得分:0)

public class JavaHashSetTest {


    public static void main(String[] args) {
        Set<Integer> hashset= new HashSet<Integer>();

        hashset.add(null);
        hashset.add(22);
        hashset.add(222);
        hashset.add(null);
        hashset.add(11);
        hashset.add(233);
        //  TreeSet<String> tset=hashset;

      Iterator<Integer> it = hashset.iterator();
        while(it.hasNext()){
            Integer i = it.next();
            System.out.print(i+" ");
        }
    }

}

我的代码正在运行,为什么它会给你Nullpointer 我试图对包含Null值的hashset进行排序,然后它会给你异常,否则它工作正常。

答案 7 :(得分:0)

只有TreeSet将获得运行时间Null pointer Exception,而HashSet在编译时将不会出现任何错误,并且在运行时它将仅允许一个null值,如果输入除此之外,它还会超过HashSet。看到这里:

public class HasSetDemo {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //no error it will print only one null and 2,5,8
        Set<Integer> s = new HashSet<Integer>();
        s.add(2);
        s.add(5);
        s.add(8);
        s.add(null);
        s.add(null);//it will override and hashset will allow one null value
        Iterator i=s.iterator();        
        while(i.hasNext()){
            Object in=(Object)i.next();
            System.out.println(" hi "+in);
        }
    }
}

输出

hi null
hi 2
hi 5
hi 8

情况2:

public class SetDemo {

    public static void main(String[] args) {
        // either its may be string or integer it will give NullPointerException in run time
        Set<String> s2 = new TreeSet<>();
        s2.add("ramana");
        s2.add(null);
        s2.add("4");
        s2.add("5");
        s2.add(null);
        Iterator<String> i=s2.iterator();       
        while(i.hasNext()){
            System.out.println(i.next());
        }
    }
}

输出:

Exception in thread "main" java.lang.NullPointerException
    at java.util.TreeMap.put(Unknown Source)
    at java.util.TreeSet.add(Unknown Source)
    at com.sagili.set.SetDemo.main(SetDemo.java:13)

答案 8 :(得分:-1)

将空值添加到集合(如HashSet Arraylist)只有在使用集合进行排序时才会产生问题。除此之外,null将适用于迭代器和正常场景,以显示列表或集的内容。

答案 9 :(得分:-1)

Set interface在内部使用HashMap实现类。当我们使用add()时,我们提供的值作为值的关键存储在Map中,它会创建一个空对象。

因此,地图不允许重复。