Removing Null Values In A List Using Java 8 Stream

The other day, I was working on a huge JSON object that had a number of collections in it. The entire object had to be saved into a relational database, which means I was mapping out the raw JSON data to its logical representation as database tables.

Though the object wasn’t that complicated, it did come with a lot of unique fields. Hundreds. It is such a tedious chore to map out all of those properties. Plus, the datasource is a third party, and the object definition I have of the payload wasn’t that up-to-date. Not to mention discovering unknown object properties. Like I said, the definition wasn’t entirely complete.

The problem came in when I was extracting objects that were nested in a list of objects. One of those objects had an unexpected value of null. It wasn’t represented as an empty object {}, or the field omitted.

Actually, null values for objects is not uncommon. Especially if the producer of such JSON objects is using loosely typed languages such as PHP or Perl.

For example it looked something like this JSON object below. Notice the extras field is an object, with a null on the second one.

{
	"customer": {
		"name": "Joey",
		"address": "3 Green Meadow Lane",
		"bag": [{
			"quantity": 2,
			"name": "cheese hamburger",
			"custom": {
				"patty": "wagyu beef",
				"onion_type": "white"
			},
			"extras": {
				"onions": true,
				"lettuce": true,
				"ketchup": 3
			}

		}, {
			"quantity": 1,
			"name": "regular hamburger",
			"custom": {
				"onion_type": "white"
			},
			"extras": null

		}]
	}

}

As every Java developer has learned from early on, it is good to check for nulls. Working on a null value in that list caused an exception in my case. While I did check for nulls, it was just that I lacked one layer of check, and thus the error.

Now, to translate that into Java code. I can work on lists through the Java Stream API like so.

Customer customer = objectMapper.readline(jsonString, Customer.class);
List<Extra> extrasList = customer.getBag().stream()
        .filter(Objects::nonNull)
        .map(bag -> {
            Extra extra = bag.getExtra();
            extra.setDefaults(true);
            return extra;
        })
        .collect(Collectors.toList());

The filter() operation above checks for null on the Bag objects and skips it if the condition is true. There should have been an additional filter to check if the nested object I’m tring to extract into a list is not null. Which is where the fault lies. I was not being thoroughly careful.

Customer customer = objectMapper.readline(jsonString, Customer.class);
List<Extra> extrasList = customer.getBag().stream()
        .filter(Objects::nonNull)
        .filter(bag -> bag.getExtra() != null)
        .map(bag -> {
            Extra extra = bag.getExtra();
            extra.setDefaults(true);
            return extra;
        })
        .collect(Collectors.toList());

Now, the code block above has a second filter checking whether the Extra object is null or not.

It is important to note that filtering out for null objects is made prior to doing a map() operation in my examples. Not doing so can have unintended consequences.

Having a null in a list is fine. It is not wrong. But doing some operations with it inside can, in different ways, wreak havoc on the behavior of an application. Your use-case might be different.

Similar Posts: