42

Say I have a List and I know that I never want to add null to it. If I am adding null to it, it means I'm making a mistake. So every time I would otherwise call list.add(item) I would instead call if (item == null) throw SomeException(); else list.add(item);. Is there an existing List class (maybe in Apache Commons or something) that does this for me?

Similar question: Helper to remove null references in a Java List? but I don't want to remove all the nulls, I want to make sure they never get added in the first place.

Community
  • 1
  • 1
Tyler
  • 21,762
  • 11
  • 61
  • 90
  • 1
    Couldn't you just subclass the List class and add the functionality you just listed? – Nick Radford Jun 22 '11 at 00:15
  • 1
    This is a pretty bespoke requirement; `null` is a perfectly acceptable value to hold in a container (in most circumstances). So you'll probably need to roll your own wrapper. – Oliver Charlesworth Jun 22 '11 at 00:16
  • @Nick I could, but I would have to override (at least, off the top of my head) `add`, `addAll`, plus a constructor or two. It probably wouldn't be that hard but I suspect someone (Apache, Google...) has already done it, and has caught a subtle bug somewhere that I would likely miss. – Tyler Jun 22 '11 at 00:26
  • @Oli Well the Collections API is quite clear in allowing a Nullpointer exception in case the collection doesn't support nulls. So clearly the API considers this case and decides otherwise. – Voo Jun 22 '11 at 00:56
  • I just happened to discover this: http://www.kiwidoc.com/java/l/p/commons-collections/commons-collections/3.2.1/p/org.apache.commons.collections/c/CollectionUtils#addIgnoreNull%28Ljava%2Futil%2FCollection%3BLjava%2Flang%2FObject%3B%29 which doesn't really answer my original question but serves a similar purpose. – Tyler Jun 23 '11 at 00:06

9 Answers9

31

Watch out -- several answers here are claiming to solve your problem by wrapping a list and checking in add and addAll, but they're forgetting you can also add to a List via its listIterator. It's challenging to get a constrained list right, which is why Guava has Constraints.constrainedList to do it for you.

But before looking at that, first consider whether you only need an immutable list, in which case Guava's ImmutableList will do that null checking for you anyway. And in the off chance that you can use one of the JDK's Queue implementations instead, that'll do it too.

(Good list of null-hostile collections: https://github.com/google/guava/wiki/LivingWithNullHostileCollections)

Daniel Trebbien
  • 38,421
  • 18
  • 121
  • 193
Kevin Bourrillion
  • 40,336
  • 12
  • 74
  • 87
20

Use Apache Commons Collection:

ListUtils.predicatedList(new ArrayList(), PredicateUtils.notNullPredicate());

Adding null to this list throws IllegalArgumentException. Furthermore you can back it by any List implementation you like and if necessary you can add more Predicates to be checked.

Same exists for Collections in general.

Use Google Guava:

Constraints.constrainedList(new ArrayList(), Constraints.notNull())

Adding null to this list throws NullPointerException.

Fabian Barney
  • 14,219
  • 5
  • 40
  • 60
6

AFAIK, there is no standard implementation available in the JDK. However, the Collection spec says that NullPointerException should be thrown when a collection does not support nulls. you can use the following wrapper to add the functionality to any Collection (you'll have to implement the other Collection methods to delegate them to the wrapped instance):

class NonNullCollection<T> implements Collection<T> {

    private Collection<T> wrapped;
    public NonNullCollection(Collection<T> wrapped) {
        this.wrapped = wrapped;
    }
    @Override
    public void add(T item) {
        if (item == null) throw new NullPointerException("The collection does not support null values");
        else wrapped.add(item);
    }
    @Override
    public void addAll(Collection<T> items) {
        if (items.contains(null)) throw new NullPointerException("The collection does not support null values");
        else wrapped.addAll(item);
    }
    ...
}
Ryan Gross
  • 6,423
  • 2
  • 32
  • 44
  • +1 Yup that's how I'd do it too - apart from the obvious typing error in addAll. Pretty much copy & paste for the other methods, so not much work. +1 – Voo Jun 22 '11 at 00:54
  • 1
    Consider throwing `IllegalArgumentException` as null is an illegal argument. See http://stackoverflow.com/questions/3881/illegalargumentexception-or-nullpointerexception-for-a-null-parameter – Steve Kuo Jun 22 '11 at 01:42
  • 2
    @Steve Kuo: I only throw NullPointerException because that is what the Collection javadoc says to throw if the Collection does not support nulls. – Ryan Gross Jun 22 '11 at 02:02
  • This is not terrible, but it's a lot of tedious code like `public T get(int i) { return wrapped.get(i); }`, which is why I was hoping for a one-liner answer like Fatal's. – Tyler Jun 22 '11 at 11:25
  • Link is broken. – corvus_192 Oct 10 '17 at 16:20
4

If it's ok to create a list and not mutate existing one, List.of added in Java 9 throws NPE when element added is null

Piotr Cierpich
  • 427
  • 2
  • 11
4

This might help you if you want to add an item to the list and silently ignore if the value is null:

You need Apache Commons Collections 4:

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.4</version>
</dependency>

Then, you need to import:

import org.apache.commons.collections4.CollectionUtils;

Now, use it like:

List<String> someList = new ArrayList<>();
String nullItem = null;
String normalItem = "Text";

CollectionUtils.addIgnoreNull(someList, nullItem);
CollectionUtils.addIgnoreNull(someList, normalItem);

Eventually, someList will just have 1 item. null will be ignored.

1

Although this problem sort of yells "delegate", it's much easier with subclassing since you intend to inherit almost all the same functionality.

class MyList extends List {

  //Probably need to define the default constructor for the compiler

  public add(Object  item) {
    if (item == null) throw SomeException();
    else super.add(item);
  }    

  public addAll(Collection c) {
    if (c.contains(null)) throw SomeException();
    else super.addAll(c);
  }
}
Jeremy
  • 5,365
  • 14
  • 51
  • 80
  • 1
    You ought to override addAll as well. – joeslice Jun 22 '11 at 00:25
  • 4
    See my comment to Nick above. Also, I would have to extend a concrete class like ArrayList which means I would have to do all the work all over again if I later needed, say, a LinkedList that didn't allow nulls. So then I think, hm, maybe it should just be a utility method that wraps an existing list, kind of like `Collections.unmodifiableList` is. And then I think, wait, maybe someone has already gone through all this. – Tyler Jun 22 '11 at 00:28
  • @MatrixFrog See my answer. Apache Commons Collection offers Predicate decorators for Lists and Collections in general. You can back it with List/Collection implementation you like and it is not restricted to check for not null only, but of course it can be used for not null check only. – Fabian Barney Jun 22 '11 at 09:50
1

You might do this by just wrapping an instance of a List and providing the null-checked add method. In other words, your class would just have a couple of methods and in inner variable.

If you need the full functionality of a list, you might consider Guava's (used to be Google Collections) ForwardingList.

Another approach is to just extend List, but the gotcha there is that you need to override both add and addAll.

Interestingly, guava has a standardAddAll, which can be used as the implementation of addAll, which solves at least part of the problem.

joeslice
  • 3,454
  • 1
  • 19
  • 24
  • Of course, if you're using Guava you can (and should) just write `Constraints.constrainedList(list, Constraints.notNull())` as Kevin B mentioned in his answer here. – ColinD Jun 27 '11 at 15:45
0

This should work

List<String> list = Collections.checkedList(new ArrayList<String>(), String.class);
try {
    list.add(null);
    throw new AssertionError("Expected a NPE");
} catch (NullPointerException expected) {
    System.out.println("list.add(null); threw "+expected);
}
try {
    List<String> list2 = Arrays.asList("", null);
    list.addAll(list2);
    throw new AssertionError("Expected a NPE");
} catch (NullPointerException expected) {
    System.out.println("list.addAll(\"\", null); threw " + expected);
}

however a bug in the addAll implementation means you need to use the following

List<String> list = Collections.checkedList(
   Collections.checkedList(new ArrayList<String>(), String.class), String.class);

and you get

list.add(null); threw java.lang.NullPointerException
list.addAll("", null); threw java.lang.NullPointerException
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    Isn't that actually a bug in the `add` implementation? As I said on mP's answer, the doc says: "Since null is considered to be a value of any reference type, the returned list permits insertion of null elements whenever the backing list does." http://www.kiwidoc.com/java/l/p/java/j2se/1.6/p/java.util/c/Collections So it seems to me that `add` is right and `addAll` is wrong. – Tyler Jun 22 '11 at 09:26
  • I agree its inconsistent with the javadoc. The typeCheck code just does `if(!type.isIntance(o))` there is no special handling for `null` to allow it. Personally this is the behaviour I would want. – Peter Lawrey Jun 22 '11 at 09:35
  • I guess I would agree that it's what I would want; I'm not sure. But I'm inclined to think that in future Java releases, the docs will stay the same and the code will change to match the docs, not the other way around, right? If `checkedList` worked exactly the way the docs say it does, then `checkedList(x)` and `checkedList(checkedList(x))` would both allow adding nulls, if x allowed adding nulls. So that means upgrading to a newer version of Java would change the behavior of this code. – Tyler Jun 22 '11 at 10:35
  • @MatrixFrog, I would agree that it happens to work now, possibly due to a bug. I have reported it as an issue to the Java Bug Database so it could be changed soon. If you want to track Null values perhaps you can use an approach like IntelliJ does http://www.jetbrains.com/idea/webhelp/nullable-and-notnull-annotations.html It instruments runtime checks, but also does static analysis. – Peter Lawrey Jun 22 '11 at 11:10
  • Cool. Do you have a link to that bug so I can track its progress? – Tyler Jun 22 '11 at 17:09
  • http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7057808 no sure how long it takes before you can see it. – Peter Lawrey Jun 22 '11 at 17:13
  • Just noticed my first comment is wrong. I meant to say: "So it seems to me that `add` is wrong and `addAll` is right." Though in fact both methods are wrong. See my comment on the bug page... – Tyler Jun 24 '11 at 02:59
  • 1
    That bug's been known for years; I doubt they'll fix it. – Kevin Bourrillion Jun 27 '11 at 14:49
  • 1
    @KevinBourrillion I think it's fixed by the report. – Mark Dec 24 '17 at 03:48
  • 1
    THIS NO LONGER WORKS. In Java 11 (maybe earlier versions too) the `add` and `addAll` methods explicitly check and allow for `null` before using instanceof. – Klitos Kyriacou Feb 06 '19 at 15:56
-1

try Collections.checkedList().

mP.
  • 18,002
  • 10
  • 71
  • 105
  • 1
    I don't think that helps. "Since null is considered to be a value of any reference type, the returned list permits insertion of null elements whenever the backing list does." http://www.kiwidoc.com/java/l/p/java/j2se/1.6/p/java.util/c/Collections – Tyler Jun 22 '11 at 04:23
  • 1
    This collection does an isInstance which prevent nulls being added. A bug in the code allows nulls to be added with addAll(). The workaround is to wrap the collection twice. ;) – Peter Lawrey Jun 22 '11 at 08:27