Ijaz
Ijaz

Reputation: 461

What are the java collections accepts adding null values?

I know Set and Map accepts null values and today I just found out LinkedList also accepts null values like

   map.put(null, 1);
   set.add(null);
   linkedList.add(null)

Is there any other collections that allow null values to be stored?. Just posting to get a comprehensive list in one place and reason for each for them.

Upvotes: 8

Views: 14242

Answers (3)

Giorgi Tsiklauri
Giorgi Tsiklauri

Reputation: 11120

Set and Map are interfaces. They have several implementations in Java.

Popular implementations of the Map are:

  1. HashMap - accepts one null key
  2. Hashtable - doesn't accept any null key
  3. TreeMap - doesn't accept any null key
  4. LinkedHashMap - accepts one null key

Any number of null values can be added as value in any of above implementations


Popular implementations of the Set are:

  1. HashSet - accepts one null element
  2. TreeSet - doesn't accept any null element
  3. LinkedHashSet - accepts one null element

Any implementations of List, like ArrayList or LinkedList can accept nulls.

Upvotes: 10

Rabah LEKHEBASSENE
Rabah LEKHEBASSENE

Reputation: 31

This problem can be resolved by using placeholder class Optional from JDK.

The principle is to package a nullable value within an wrapper instance using Optional class that will carry values (null values also).

It can be annoying and little heavy in the code but surely can be suitable in many cases.

Here is an example with a non-null value :

Optional<Integer> valuedInt = Optional.ofNullable(123);
assertTrue(valuedInt.isPresent());          
assertEquals(Integer.valueOf(123), valuedInt.get());

Here is an example with a null value :

Optional<Integer> nullInt = Optional.ofNullable(null);
assertTrue(nullInt.isEmpty());
try {
    var val = nullInt.get();
} catch (Exception e) {
    // Invocation of nullInt.get() throws an exception.
    assertTrue(e instanceof NoSuchElementException);
}
            
// However, the method Optional.orElse(T) can be used as
// a getter that supplies the value wether it is valued or null.
assertEquals(Integer.valueOf(123), valuedInt.orElse(null));
assertEquals(null,                 nullInt.orElse(null));

We can initialize a list as so :

// Our hacked list
List<Optional<Integer>> integersOpt;

First way to populate the list :

integersOpt = new ArrayList<>();
integersOpt.add(Optional.ofNullable(1));
integersOpt.add(Optional.ofNullable(null));
integersOpt.add(Optional.ofNullable(2));
integersOpt.add(Optional.ofNullable(null));
integersOpt.add(Optional.ofNullable(3));

Second way to populate the list (unmodifiable) :

integersOpt =
    Arrays.asList(1, null, 2, null, 3).stream()
    .map(x -> Optional.ofNullable(x))
    .collect(Collectors.toList());

Third way to populate the list (modifiable) :

integersOpt =
    new ArrayList<>(
        Arrays.asList(1, null, 2, null, 3).stream()
        .map(x -> Optional.ofNullable(x))
        .collect(Collectors.toList())
    );

Count and print values :

int countNulls = 0, countNonNulls = 0;
for(Optional<Integer> opt : integersOpt) {
    Integer optVal = opt.orElse(null); // Our famous "getter" function.
    if(optVal == null) {countNulls++;}
    else               {countNonNulls++;}
    System.out.println("Original value = " + optVal);
}

assertEquals(2, countNulls);
assertEquals(3, countNonNulls);
            

integersOpt.toString() will return this value :

[Optional[1], Optional.empty, Optional[2], Optional.empty, Optional[3]]

Upvotes: 3

Eugene
Eugene

Reputation: 120868

Accepting nulls was a design mistake, as time has proven. First of all this complicates implementations, because at some point in time you might need to be able to compare null to null, for example; and this sometimes require special handling (or special branches in the code at least).

Since java-9, immutable collections all reject null and even document it properly. One minor example (but there are many more) is Set:of, that says:

@throws NullPointerException if the element is null

Not only that, but they also don't allow null checks, so you might be surprised by this a bit:

    Set<Object> oldS = new HashSet<>();
    oldS.add(new Object());
    System.out.println(oldS.contains(null)); // false

    Set<Object> newS = Set.of(new Object());
    System.out.println(newS.contains(null)); // NPE

Every new collection or implementation that comes to JDK prohibits null.

Upvotes: 3

Related Questions