Reputation: 461
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
Reputation: 11120
Set
and Map
are interfaces. They have several implementations in Java.
Popular implementations of the Map
are:
HashMap
- accepts one null
keyHashtable
- doesn't accept any null
keyTreeMap
- doesn't accept any null
keyLinkedHashMap
- accepts one null
keyAny number of null
values can be added as value in any of above implementations
Popular implementations of the Set
are:
HashSet
- accepts one null
elementTreeSet
- doesn't accept any null
elementLinkedHashSet
- accepts one null
elementAny implementations of List
, like ArrayList
or LinkedList
can accept null
s.
Upvotes: 10
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
Reputation: 120868
Accepting null
s 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