34

I want to know why HashSet, LinkedHashSet and TreeSet implementation does not allow null elements? Whenever i try to run the following code it throws a null pointer exception.

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+" ");
    }
    }

Please guide me.

Joshua Goldberg
  • 5,059
  • 2
  • 34
  • 39
nakul
  • 1,445
  • 7
  • 20
  • 30
  • 24
    Misleading title. E.g. the `HashSet` documentation explicitly states *This class permits the null element.* – Abdull Apr 18 '16 at 09:23
  • HashSet and LinkedHashSet allows null values. Only, TreeSet does not allow it. – S Kumar Sep 13 '21 at 06:43

11 Answers11

71

This is why I don't like to rely on auto-boxing. Java Collections cannot store primitives (for that you will need a third party API like Trove). So, really, when you execute code like this:

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

What is really happening is:

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

Adding a null to the hash set is not the problem, that part works just fine. Your NPE comes later, when you try and unbox your values into a primitive int:

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

When the null value is encountered, the JVM attempts to unbox it into an the int primitive, which leads to an NPE. You should change your code to avoid this:

while(it.hasNext()){
    final Integer i = it.next();
    System.out.print(i+" ");
}
Perception
  • 79,279
  • 19
  • 185
  • 195
  • 11
    Actually `2` is autoboxed by calling `Integer.valueOf(2)` – Steve Kuo Feb 08 '13 at 17:51
  • 1
    I am adding null to ArrayList and it is not throwing NPE.{ ArrayList list = new ArrayList(); System.out.println("initial size of array is:"+list.size()); list.add(4); list.add(2); list.add(8); list.add(9); list.add(3); list.add(7); list.add(1); list.add(null); list.add(0,12); Iterator iterator = list.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } – nakul Feb 08 '13 at 22:51
  • 10
    @nakul - `ArrayList` allows null elements, just like `HashSet`. The problem with your code has nothing to do with adding to `HashSet`, it has to do with retrieving elements from the `HashSet` into a primitive. – Perception Feb 08 '13 at 23:36
  • Yeah, storing null to primitives is not allowed in java. – swapyonubuntu Sep 21 '16 at 11:14
  • "This is why I don't like to rely on auto-boxing", why should null be autoboxed to 0 ? null != 0 – JacksOnF1re Jul 06 '17 at 14:06
21

1) Are you sure about you get compile time error? I don't think so, I guess the code throws NPE at runtime at

int i = it.next();

2) As a matter of fact java.util.Set interface does not forbid null elements, and some JCF Set implementations allow null elements too:

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.

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

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
8

No, Set Interface do allow null value only its implementation i.e. TreeSet doesn't allow null value.

even though you have not written iteration code and have only oTreeSet.add(null) in your code it compiles and at runtime it throws NullPointerException.

TreeSet class's add() method internally calls put() method of TreeMap class. null value is not allowed as below code in put() method

if (key == null)
     throw new NullPointerException();
Shrikant Dande
  • 223
  • 1
  • 5
  • 17
5

The point of the Set interface is to use information about the elements (either hashcodes or comparisons) to make the implementation faster.

null doesn't have that information.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 3
    While it is true that most implementations won't accept `null`, `null` is perfectly unique from a `Set` point of view. The docs state that ["Some set implementations have restrictions on the elements that they may contain"](http://docs.oracle.com/javase/7/docs/api/java/util/Set.html); this is not universal for all implementations by definition (though the answer is valid for the code OP provided). – akaIDIOT Feb 08 '13 at 14:36
4

Set Interface does not allow null because in TreeSet, It stores element in sorting order so every time we add new element then it compares value and then it sorts. so internally what happening is it compares new added null value with existing values so it will throw NullPointerException.

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

Thats why it does not allow null values.

Sajid Patel
  • 115
  • 1
  • 1
  • 7
2

You have mentioned:

// hashSet.add(null); will throw null pointer

This is not correct as a HashSet does allow a null to be added to it and therefore, you won't face any compilation failure or runtime exception for this statement. However, when the following statement will be executed

int i = it.next();

you will get a runtime exception as shown below:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Iterator.next()" is null at Main.main(Main.java:24)

The exception is self-explanatory. The JLS §5.1.8 specifies it as follows:

If r is null, unboxing conversion throws a NullPointerException

Given below is another example to understand this concept:

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

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

Output:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because "x" is null at Main.main(Main.java:7)

In fact, the compiler warns you beforehand:

Null pointer access: this expression of type Integer is null but requires auto-unboxing

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
1

Set allows adding null so that is not a problem. Secondly Java program needs to be compiled first to convert it in byte code and then it is executed. NullPointerException is an exception thrown during run-time. Compile time it should not be a problem. Now lets analyse as why you get NPE.

Iterator here is supposed to output the object of type Integer and we wish to store the result in primitive type int variable. Integer is a class which can have the references of its type to reference to null but the primitives can not hold null values.

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+" ");
}

When int i = it.next(); is executed then public int intValue() is invoked to convert the Object of Integer to primitive int. When it.next() returns null then the null.intValue() is executed which results in NullPointerException.

if Integer is used instead of int then there will be no exception

Integer i = it.next();
nits.kk
  • 5,204
  • 4
  • 33
  • 55
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+" ");
        }
    }

}

My code is working and why it will give you Nullpointer I have tried to sort hashset which contain Null value then it will give you exception else it works fine.

Joel
  • 7,401
  • 4
  • 52
  • 58
  • 2
    Your code works because you have used 'Integer i = it.next();' In case you use 'int i = it.next();' then you will get the exception. Iterator is supposed to give Integer type object from its next() method and when we try to store it in primitive type then intValue() defined in Integer.java is invoked. Since the reference is null hence it is invoked on a null and it results in NPE. – nits.kk Apr 10 '16 at 16:52
0

Only TreeSet will get run time Null pointer Exception and HashSet wont get any error at compile time, and run time it will allow only one null value, If we enter more than this it will over ride in HashSet. See here:

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);
        }
    }
}

Outputs

hi null
hi 2
hi 5
hi 8

Case 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());
        }
    }
}

Outputs:

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)
Teocci
  • 7,189
  • 1
  • 50
  • 48
-1

Adding null to the collections like HashSet Arraylist will create problem only when the collection is used to sort. Other than that null will work for iterator and normal scenario to display the contents of the list or set.

-1

Set interface internally uses HashMap implementation class. When ever we use add() our provided value is stored into Map as key for value it creates a empty object.

So, map doesn't allow duplicates.

  • "Set interface internally uses HashMap". No. Some of the standard implementations of Set may use a HashMap. But the interface does not force you to do so. – JacksOnF1re Jul 06 '17 at 14:10