So, after considering code blocks yesterday, what about another bane of Java life, nulls. How could they be simplified in a Java-friendly style?
Here's the use case I'm trying to solve:
public isFromBritain(Profile profile) { if (profile != null) { Person person = profile.getPerson(); if (person != null) { Address address = person.getAddress(); if (address != null) { return "GB".equals(getCountry()); } } } return false; }
And here is my proposed solution for JDK1.6:
public isFromBritain(Profile profile) { return profile#getPerson()#getAddress()#getCountry()#equals("GB"); }
A bit surprising at first glance, yet much much simpler to read and understand. I'm using # to indicate "ignore null for now and continue processing". I used # as javadoc already uses it instead of a dot. Implementation-wise, the compiler would expand it to the former use-case, so no big issues there.
By the way, this series of entries is inspired by Graham Hamilton's blog about boilerplate Java code. I'm just trying to show what gets in my way, and provide a Java-style (not Ruby/c#/python/... style) solution. As always, opinions welcome :-)
I think a better way would be to avoid using nulls as much as possible. Too many methods rely on 'null' as a magic value.
ReplyDeleteFor methods that can return null, special annotations interpreted by static checkers such as findbugs.sf.net, ESC/Java, nice.sf.net, and IntelliJ can detect possible NPE errors. You mark a method argument or return with @Nullable if it might return null. The static checker will signal a warning in your IDE.
http://www.jetbrains.com/idea/features/newfeatures.html#nullable
http://findbugs.sourceforge.net/bugDescriptions.html#NP_NONNULL_RETURN_VIOLATION
What is wrong with the old NullObject pattern?
ReplyDeletepublic isFromBritain(Profile profile) {
return profile.getPerson().getAddress().getCountry().equals("GB");
}
Still seems more intuitive to me...
Interesting.
ReplyDeleteOne question stays open, though: when you say "ignore null", what do you mean? Should the result be true, in that case? Or false?
What's even more interesting, is that this question is not answered in the "original" code block either ;-)
Actually when I wrote it I realised that the equals question was interesting. However this actually highlights a flaw in the current equals method:
ReplyDeletea.equals(null) == false
null.equals(a) == NPE
This is a violation of equals() symmetry requirements, we've just all ignored it until now.
Thus, my proposal also adds:
null#equals(a) == false
a#equals(null) == false
null#equals(null) == true
On NullObject, its a lot of extra effort, is only suitable for code you control, and where you trust all your developers.