💾 Archived View for capsule.dotslashme.com › gemlog › posts › 2019-01-11-null-exception.gmi captured on 2024-03-21 at 15:11:08. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2024-02-05)
-=-=-=-=-=-=-
published on 2019-01-11
--//# best-practices # java # null
Besides being a boy scout, I'm also a code minimalist and believe that good design will take you much further, than being able to produce the one-liner of the century. One reason for this belief is that with good design come sensible defaults and mechanisms that will help you keep your code clean and more safe by default. Today I will talk about _null_ and why I think it should be avoided like the plague, or at the very least be treated like an exception.
Look through any random piece of software written in Java. What do you find? My guess is lots and lots of defensive statements like _if (var == null)_. Just focus on the code for a bit, look at the amount of effort expended on checking for null, making sure we have null, making sure we don't have null. Is that what you would call effective code?
I know of course it's not, but let me argue for why it should be treated as such. Does _null_ represent an error or at least a warning in your program? Do you have to handle a _null-case_ if it occur? In most cases, this is true, so why then would you treat _null_ any different from an exception?
Null should be handled as soon as possible and then turned into something more manageable, like empty.
This is the simplest, don't allow your code to return null anywhere where it should return a collection. Go back and read How empty can you be?[1] for a way to handle these cases with empty instead. Don't forget to reduce returns to a single one, like below:
List<String> getStringList() { return getStringsFromDb() .stream() .findAny() .orElse(Collections.emptyList()); }
or if your underlying layer must return null:
List<String> getStringList() { List<String> stringList = getStringsFromSomePlace(); if (stringList == null) { stringList = Collections.emptyList(); // Java 5+ stringList = List.of(); // Java 9+ } return stringList; }
For single objects such as pojos, beans or other singlets, there are multiple strategies that you can use, but I prefer Optional:
Optional<String> getString() { String data = getStringFromSomePlace(); return data == null ? Optional.empty() : Optional.of(data); }
Again, there are a multitude of options to use, but the defense I prefer is to use Objects.requireNonNull() in your setters and your constructors:
public Bean { private String data1; private String data2; private Boolean isRequired; public Bean(String data1, String data2, Boolean required) { Objects.requireNonNull(data1); Objects.requireNonNull(data2, "data2 cannot be null"); Objects.requireNonNull(required); } }
You cannot always avoid null checks, but you can minimize the use of them by catching null early, and just like exceptions handle them properly.
© dotslashme