43

Given the following List:

List<String> list = new ArrayList<String>(); list.add("s1"); list.add("s2"); list.add(null); list.add("s3"); list.add(null); list.add("s4"); 

I need a helper class that removes null references. Something like:

SomeHelper.removeNullReference(list);

such that the list only contains "s1", "s2", "s4", "s4" (non-null references).

What should I use to fulfill this requirement?

5 Answers 5

120
list.removeAll(Collections.singleton(null)); 
Sign up to request clarification or add additional context in comments.

6 Comments

Cool, I didn't know about singletonList(). That's more elegant than my three-liner.
The Collections and Array classes are true treasure troves - and singletonList() as well as emptyList() are the main reasons why using ArraList or Vector as method parameter type anywhere should be punished with at least 20 lashes.
It could also have been list.removeAll(Arrays.asList(null)), but singletonList is slightly quicker.
And it's downwards compatible to pre-varargs Java versions.
Edited to remove four unnecessary characters, hope that wasn't the wrong thing to do.
|
18

Java 8 added Collection.removeIf(Predicate) that removes all elements matching the predicate, so you can remove all occurrences of null from a list (or any collection) with

list.removeIf(Objects::isNull); 

using java.util.Objects.isNull as a Predicate.

You can also use .removeIf(x -> x == null) if you prefer; the difference is very minor.

Comments

3

If you can control the instantiation of the List then you could prevent the nulls being added by writing a custom List implementation such as:

public class NoNullsList<E> extends ArrayList<E> { public void add(int index, E element) { if (element != null) { super.add(index, element); } } public boolean add(E e) { return e == null ? false : super.add(e); } } 

AFAIK, you don't need to override addAll because the ArrayList implementation thereof calls add.

List<String> list = new NoNullsList<String>(); list.add("s1"); list.add("s2"); list.add(null); list.add("s3"); list.add(null); list.add("s4"); 

5 Comments

These add methods violates the contract of List.add (or actually Collection.add). If you want to forbid null elements, throw an Exception (like IllegalArgumentException) there instead of returning false.
@PaŭloEbermann When you create a Class for the express purpose of ignoring nulls (not disallowing nulls as you can see from the OP), it doesn't make any sense to throw an Exception in the (expected) case of a null being added.
@Thor84no ...and then you get strange failures from library code that expects to get back the nulls it just added, or that calling add three times increases size() by three. (And you report a bug to the library developers and everyone's time is wasted.)
@JeffreyBosboom If someone uses the class NoNullsList<E> and expect the nulls to be added, they probably need to read more carefully (perhaps it should be made final). Either way, throwing an exception specifically does not solve the OP's problem. He requested a way of ignoring them, not of having Exceptions thrown. In this situation, nulls are allowed, but should be ignored - they are expected, not exceptional. Feel free to provide an alternative, but shooting this down with suggestions that would actively break this as a solution for OP is not useful.
The assumption that ArrayList.addAll will call add might have been true back in 2011, I don’t know, but nowadays, it’s definitely wrong and this code does not work; a simple statement like list.addAll(Arrays.asList("foo", null, "bar", "baz")); will break it. So it’s a good example why programmers should not subclass implementation classes in that way. If you want other examples of how this anti-pattern can fail, look at this one. You can use this to derive other cases where this approach will fail, e.g. list.replaceAll(x -> null);.
3

A drawback of Don's approach is that it extends from ArrayList. That may be good enough for now, but what happens when you want to use a different List implementation? You could make a NoNullsLinkedList and a NoNullsCopyOnWriteArrayList, etc, but then you wind up with a bunch of little classes that differ only in their extends clause. It might be better to create a List wrapper that doesn't accept null values. For example:

public class NonNullList<E> extends AbstractList<E> { private final List<E> delegate; public NonNullList(List<E> delegate) { this.delegate = delegate; } @Override public E get(int index) { return delegate.get( index ); } @Override public int size() { return delegate.size(); } @Override public E set(int index, E element) { return delegate.set( index, element ); } @Override public void add(int index, E element) { if( element != null ) { delegate.add( index, element ); } } @Override public E remove(int index) { return delegate.remove( index ); } } 

It's more code, but now you have the flexibility of choosing a List implementation when you create the object.

A possible problem is that you can still insert nulls into the underlying List object. Don's approach doesn't have the same limitation.

2 Comments

As well as Don's response, your class violates the contract of List.add (or actually Collection.add). When the add method returns (either true or false), the element should be guaranteed to be an element equal to the supplied one, which your implementation doesn't. Throw an exception instead, or at least prominently document that you violate the contract.
You are overriding the set method, but not performing any null check, which makes the entire thing pointless. But as @PaŭloEbermann already mentioned, even when fixing this issue, it would violate the general contract of List.
3

I really like the Java 8's new concise solution, I believe you should use that whenever possible.

list.removeIf(Objects::isNull); 

On the other side, if you are looking for a simple implementation to learn how it could be done, such as a helper class that returns new non-null list, you can take a look at the following code. It can also be made to accept generic types, for the sake of simplicity I used the same collection type (as in the question) in the helper class.

package removenullrefdemo; import java.util.ArrayList; import java.util.List; import java.util.Objects; class ListHelper { public static List<String> removeNullReference(List<String> list) { List<String> newList = new ArrayList<>(); list.forEach(item -> { if (item != null) newList.add(item); }); return newList; } } public class Main { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("s1"); list.add("s2"); list.add(null); list.add("s3"); list.add(null); list.add("s4"); println("Items:"); list.forEach(item -> println(item)); // Remove null refs println("Items (after nulls removed):"); boolean useJava8removeIf = false; if (useJava8removeIf) { println("Using Java8 removeIf method with predicate."); list.removeIf(Objects::isNull); } else { println("Using our own helper."); list = ListHelper.removeNullReference(list); } list.forEach(item -> println(item)); } static void println(String msg) { System.out.println(msg); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.