Putin has invaded Ukraine. His army is murdering innocent civilians, including children! Путин нахуй!
If you live in Russia, do not believe the state propaganda. Resist the regime and donate to humanitarian organizations.
My country, Poland, has accepted hundreds of thousands of Ukrainian refugees already. This is serious!
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:
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.