I wonder why java.util.ArrayList
allows to add null
. Is there any case where I would want to add null
to an ArrayList
?
I am asking this question because in a project we had a bug where some code was adding null
to the ArrayList
and it was hard to spot where the bug was. Obviously a NullPointerException
was thrown but not until other code tried to access the element. The problem was how to locate the code that added the null
object. It would have been easier if ArrayList
threw an exception in the code where the elements was being added.
7
This design decision appears mostly driven by naming.
Name ArrayList suggests to reader a functionality similar to arrays – and it is natural for Java Collections Framework designers to expect that vast majority of API users will rely on it functioning similar to arrays.
This in particular, involves treatment of null elements. API user knowing that below works OK:
array[0] = null; // NPE won't happen here
would be quite surprised to find out if similar code for ArrayList would throw NPE:
arrayList.set(0, null); // NPE => WTF?
Reasoning like above is presented in JCF tutorial stressing points that suggest close similarity between ArrayList and plain arrays:
ArrayList… offers constant-time positional access and is just plain fast…
If you would want a List implementation disallowing nulls, it would better be called like NonNullableArrayList
or something like that, to avoid confusing API users.
Side note there is an auxiliary discussion in comments below, along with additional considerations supporting the reasoning laid out here.
13
Null may be a valid value for an element of a list. Say your list contains elements which represent some optional data about a list of users and is stored in the same order as the users. If the extra data is populated then your list will contain the additional data otherwise the slot corresponding to a user will be null. (I’m sure there are better examples, but you get the idea)
if you don’t want to allow nulls to be added then you could wrap the array list with your own wrapper which threw when null was added.
6
ArrayList
allows null by design. It is intentional. From the javadoc:
“[ArrayList is a] resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null.”
The answer to “why” is that if it didn’t the ArrayList wouldn’t be usable in cases where it is necessary to put a null
in the list. By contrast, you can prevent an ArrayList from containing nulls by either testing values before adding them or using a wrapper that prevents this happening.
Is there any case where I would want to add null to an ArrayList?
Obviously, any case where null
has a distinct meaning. For instance it might mean that the value at a given position in the list has not been initialized or supplied.
It would have been easier if the ArrayList had thrown an exception in the code where the elements was being added.
You could easily implement that behaviour by creating a wrapper class. However, this is not the behaviour that most programmers / applications need.
0
Is there any case where I would want to add null to an ArrayList?
Sure, what about pre-allocation? You want an ArrayList
of things you can’t create yet because you don’t have enough info. Just because you can’t think of a reason why someone may want to do something doesn’t make it a bad idea. Whatever. (Now, I’m sure someone will come along and say you should instead have empty objects that fulfill some pattern they read about on some obscure blog and that programmers should really be able to write programs without ever using if
statements, blah blah.)
If you guys have a contract that there never should be null
s in a container then it’s up to you lot to make sure that contract is upheld, probably most appropriately by asserting. It would probably have taken you max 10 lines of code. Java makes it incredibly easy for you to do this sort of thing. The JDK cannot read your mind.
9
This seems to be more of a (software-)philosophic question here.
ArrayList
as a utility class is designed to be helpful in a wide context of possible use-cases.
Contrary to your hidden claim that accepting null as a valid value should be discouraged, there are many examples where the null value is perfectly legal.
The single most important reason is that null
is the do not know
equivalent of any reference type, including framework types. This implies that null cannot be replaced in any case by a more fluent version of the nothing
value.
So, lets say you store the Integers 1, 3, 7 in your arraylist at its corresponding index:
Due to some computation, you want to get the element at index 5, so what your array
should return is: “no value stored”. This could be achieved through returning null
or a NullObject. In most cases returning the built in null value is expressive
enough. After calling a method that can return null and using its return value a check of the returned value against null is quite common in modern code.
The statement
File f = null;
is valid and useful (I don’t think I need to explain why). It is likewise useful to have a collection of files, some of which may be null.
List<File> files = new ArrayList<File>();
// use my collection of files
// ....
// not using this one anymore:
files.set(3, null);
The usefulness of collections that may contain null objects proceeds directly from the usefulness of objects that may be null. It is really as simple as that.
0
It is easier to accept everything, than to be to be restrictive and then try opening up your design after the fact.
For example, what if they oracle/sun provided only NonNullableArrayList, but you wanted to be able to add a Null to your list. How would you do it? You would probably have to create an entirely different object, you couldn’t use extend the NonNullableArrayList. Instead if you have a ArrayList that takes everything, you could easily extend it, and override the add, where it doesn’t accept null values.
2
Usefullness of null?
Very much so when you go with a List of Lists to model a 2D real life plate with different positions. Half of those positions could be empty (in random coordinates) while the filled ones don’t represent a simple int or String but are represented by a complex object. If you want to keep the positional info, you need to fill the empty spots with null so that your list.get(x).get(y) doesn’t lead to nasty surprises. To counter the null exceptions you can check for null (very popular) or you can use an Optional (which I find handy in this case). The alternative would be to fill the empty spots with “junk” objects which can lead to all kinds of mess down the road. If your null check fails or is forgotten somewhere, Java will let you know. On the other hand a “junk” placeholder object which is not checked properly may pass unnoticed.