繁体   English   中英

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

[英]These Sets allow null. Why can't I add null elements?

我想知道为什么 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+" ");
    }
    }

请指导我。

这就是为什么我不喜欢依赖自动装箱。 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) 你确定你得到编译时错误吗? 我不这么认为,我猜代码在运行时抛出 NPE

int i = it.next();

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

Set 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. 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

不, Set 接口允许空值,TreeSet不允许空值。

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

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

if (key == null)
     throw new NullPointerException();

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

null没有这些信息。

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

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

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

Set 允许添加 null,因此这不是问题。 其次Java程序需要先编译成字节码再执行。 NullPointerException是运行时抛出的异常。 编译的时候应该没有问题。 现在让我们分析一下你为什么会得到 NPE。

这里的Iterator应该输出Integer类型的对象,我们希望将结果存储在primitive type 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+" ");
}

int i = it.next(); 执行然后调用public int intValue()将 Integer 对象转换为原始 int。 it.next()返回 null 时,将执行null.intValue()导致NullPointerException

如果使用 Integer 而不是 int 那么就不会有例外

Integer i = it.next();

你提到过:

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

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

int i = it.next();

你会得到一个运行时异常,如下所示:

线程“main”中的异常 java.lang.NullPointerException:无法调用“java.lang.Integer.intValue()”,因为“java.util.Iterator.next()”的返回值在 Main.main(Main.爪哇: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) 处为 null

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

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

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 值的哈希集进行排序,然后它会给你异常,否则它工作正常。

只有TreeSet会得到运行时空Null pointer ExceptionHashSet在编译时不会得到任何错误,并且运行时它只允许一个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)

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

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

所以,地图不允许重复。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM