Java 这些集合允许空值。为什么可以';我不能添加空元素吗?

Java 这些集合允许空值。为什么可以';我不能添加空元素吗?,java,null,hashset,Java,Null,Hashset,我想知道为什么HashSet、LinkedHashSet和TreeSet实现不允许空元素? 每当我尝试运行以下代码时,它都会抛出一个空指针异常 public static void main(String[] args) { HashSet<Integer> hashSet = new HashSet<Integer>(); hashSet.add(2); hashSet.add(5); hashSet.add(1); // hash

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

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+" ");
    }
    }
publicstaticvoidmain(字符串[]args){
HashSet HashSet=新的HashSet();
hashSet.add(2);
hashSet.add(5);
hashSet.add(1);
//add(null);将抛出null指针
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);
迭代器it=hashSet.Iterator();
while(it.hasNext()){
int i=it.next();
系统输出打印(i+“”);
}
}

请指导我。

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

null
没有该信息。

1)您确定会出现编译时错误吗?我不这么认为,我猜代码在运行时在

inti=it.next()

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

设置API-
不包含重复元素的集合。更正式地说,集合不包含e1和e2元素对,因此e1.equals(e2)最多包含一个空元素。

HashSet API-
此类允许空元素

LinkedHashSet API-
此类提供所有可选的集合操作,并允许空元素


TreeSet.add API-
抛出NullPointerException-如果指定的元素为null,并且此集合使用自然排序,或者其比较器不允许null元素

这就是我不喜欢依赖自动装箱的原因。Java集合不能存储原语(为此,您需要第三方API,如。所以,实际上,当您执行这样的代码时:

hashSet.add(2);
hashSet.add(5);
真正发生的是:

hashSet.add(new Integer(2));
hashSet.add(new Integer(5));
将空值添加到哈希集不是问题所在,这部分工作正常。当您尝试将值取消装箱到基本整数中时,您的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+" ");
}
公共类JavaHashSetTest{
公共静态void main(字符串[]args){
Set hashset=新hashset();
add(null);
hashset.add(22);
hashset.add(222);
add(null);
hashset.add(11);
hashset.add(233);
//TreeSet-tset=hashset;
迭代器it=hashset.Iterator();
while(it.hasNext()){
整数i=it.next();
系统输出打印(i+“”);
}
}
}
我的代码正在工作,为什么它会给你空指针
我尝试对包含Null值的hashset进行排序,然后它会给您异常,否则它工作正常。

Set允许添加Null,所以这不是问题。其次,需要先编译Java程序,将其转换为字节码,然后执行
NullPointerException
是在运行时引发的异常。编译时这应该不是问题。现在让我们分析一下为什么你会得到NPE

迭代器
这里应该输出类型为
Integer
的对象,我们希望将结果存储在
基元类型int
变量中。Integer是一个类,它可以将其类型的引用引用为null,但原语不能包含null值

Iterator<Integer> it = hashSet.iterator(); // Iterator of Type Integer
while(it.hasNext()){
    int i = it.next(); // it.next outputs Integer, but result is tried to be held in a primitive type variable
    System.out.print(i+" ");
}

仅当集合用于排序时,向集合(如HashSet Arraylist)添加null才会产生问题。除此之外,null将用于迭代器和正常场景,以显示列表或集合的内容。

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


所以,地图不允许重复

Set接口不允许null,因为在TreeSet中,它按排序顺序存储元素,所以每次添加新元素时,它都会比较值,然后进行排序。所以在内部,它将新添加的null值与现有值进行比较,从而抛出NullPointerException

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

这就是它不允许空值的原因。

否,设置接口确实允许空值只有它的实现,即
树集
不允许空值

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

TreeSet
类的
add()
方法内部调用TreeMap类的
put()
方法。
null
值是不允许的,因为put()方法中的代码如下


只有
TreeSet
将获得运行时
Null指针异常
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);
        }
    }
}
案例2: 你提到:

//add(null);将抛出空指针

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

int i = it.next();
您将获得一个运行时异常,如下所示:

线程“main”java.lang.NullPointerException中出现异常:无法 调用“java.lang.Integer.intValue()”,因为 Main.Main处的“java.util.Iterator.next()”为null(Main.java:24)

例外是不言自明的。指定如下
if (key == null)
     throw new NullPointerException();
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
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)
int i = it.next();
public class Main {
    public static void main(String[] args) {
        Integer x = null;
        print(x);
    }

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