Tuesday, 22 November 2005

Adding auto null checks to Java

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 :-)

4 comments:

  1. 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.

    For 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

    ReplyDelete
  2. What is wrong with the old NullObject pattern?

    public isFromBritain(Profile profile) {
    return profile.getPerson().getAddress().getCountry().equals("GB");
    }

    Still seems more intuitive to me...

    ReplyDelete
  3. Interesting.
    One 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 ;-)

    ReplyDelete
  4. Actually when I wrote it I realised that the equals question was interesting. However this actually highlights a flaw in the current equals method:

    a.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.

    ReplyDelete