NPE: Converting a list of objects to a map

Like every Java developer, I had a fair amount of Null Pointer Exceptions in my career. That’s why I decided to describe real-world examples I had to fix.

Today I will show you how to get an NPE while retrieving records from a database and creating a map based on these records, using streams and collectors introduced in Java 8.

Let’s say we have a Setting class:

public class Setting {
private final int accountId;
private final String type;
private final String value;

public Setting(int accountId, String type, String value) {
this.accountId = accountId;
this.type = type;
this.value = value;
}

public String type() {
return type;
}

public String value() {
return value;
}
}

Now, in another part of the system we will retrieve Setting objects from a database. We haven’t noticed that the SQL table allows NULL in the value column. Let’s pretend our list of settings looks like that:

List<Setting> settings = new ArrayList<>();
settings.add(new Setting(1, "site_title", "My blog"));
settings.add(new Setting(1, "site_description", "A place with fresh ideas"));
settings.add(new Setting(1, "site_copyright", null));

We want to easily access settings by names, so we create a map using a stream:Ponieważ chcemy mieć łatwy dostęp do ustawień o konkretnej nazwie, tworzymy mapę za pomocą strumienia:

Map<String, String> settingsMap = settings
.stream()
.collect(Collectors.toMap(Setting::type, Setting::value));

Bang! We’ve got a NPE here because one of the values used to create a map is null. It turns out that Collectors.toMap() does not handle NULLs.

Let’s think: do we really need a NULL in this case? I guess not. A NULL value means “no data” or “unknown value”, which is the same as if the setting did not exist. We should set the value column as NOT NULL. We can additionally filter the settings list:

Map<String, String> settingsMap = settings
.stream()
.filter(setting -> null != setting.value())
.collect(Collectors.toMap(Setting::type, Setting::value));

A NULL would make sense for example if we wanted to create a map between people’s names and their ages. If we don’t know someone’s age, then a null seems reasonable. We would have then to create a map in a different way.

You can have a further read on StackOverflow. Alternative ways to convert a list to a map can be found on Baeldung.