Cleaner Code with Guava Optionals and Preconditions

Cleaner Code with Guava Optionals and Preconditions

Working towards clean code is a priority for me when I develop software. For some time I’ve been using Google Guava for nearly all my projects. The reason is simple. Guava provides great facilities to beautify my code. Today I want to show you how I use Preconditions to avoid unnecessary if/throw statements and Optionals to improve my code semantics.

[ Need expert advice for your project? Our Developer Support is here to resolve your questions. | Find more tips on clean code on the Software Craftsmanship page. ]

Preconditions are not new. Apache Commons had similar functionality but not as clean as Guava’s solution. Preconditions are used for checking method arguments, states, etc. When a condition is false the Precondition will throw the expected exception. With expected I mean the following: when checking a state you can use Preconditions.checkState( condition ). If the condition is false it will throw an IllegalStateException. The same is true for other Preconditions like checkArgument which throws an IllegalArgumentException. Of course, working with Preconditions only makes sense when using static Imports. Let’s take a look at an example.

Given is a method which takes a List as an argument. When this method is invoked we want to check that the list is not null and it is not empty. A plain Java solution can look like this:

<pre lang="java">
public void doSomething( List<Object> list ) {
  if( list == null ) {
    throw new IllegalArgumentException( "List must not be null" );
  }
  if( list.isEmpty() ) {
    throw new IllegalArgumentException( "List must not be empty" );
  }
  doSomethingMore( list );
}</pre>

When using Guava’s Preconditions the amount of code is reduced significantly. The solution looks like the one below.

<pre lang="java">
public void doSomething( List<Object> list ) {
  checkArgument( list != null, "List must not be null" );
  checkArgument( !list.isEmpty(), "List must not be empty" );
  doSomethingMore( list );
}</pre>

This is an improvement for sure. But this approach becomes really sexy when it’s combined with Guava’s Optionals. Optionals are a concept designed to avoid the sick null concept (read this for understanding why I call it “sick”). They are basically a container for an object to avoid nullable references. For example, null is used most of the time to check if an object is there or not. And if it’s not there, an NPE occurs. The result is code like the following:

<pre lang="java">public void doSomething() {
  if( this.field == null ) {
    throw new IllegalStateException( "Field is not initialized" );
  }
  doSomethingMore();
}</pre>

Instead of saving the object directly as a field I often use an Optional. This avoids NPEs in my code and gives it better semantics. The example above is transformed into the one below when it’s combined with Preconditions:

<pre lang="java">public void doSomething() {
  checkState( field.isPresent(), "Argument is not initialized" );
  doSomethingMore();
}</pre>

In the end it’s up to you to decide if the code is better/cleaner with Optionals and Preconditions. From my point of view it’s definitely more speakable. I would love to hear your opinion about it in a comment ;).

12 Comments
  • Mark
    Posted at 4:03 pm, June 6, 2012

    While that definitely seems cleaner, the code still seems smelly – business logic mixed with parameter checking (etc). Annotations might help pull non-business logic out of the method. One could still argue that there is some code smell (and i would agree) but it would be less.

  • Jerome
    Posted at 4:10 pm, June 6, 2012

    You can use
    checkNotNull( list, “List must not be null” );
    instead of
    checkArgument( list != null, “List must not be null” );

  • Sebastien Gandon
    Posted at 4:44 pm, June 6, 2012

    I agree with Mark, this would defenitly look better using annotation to separate the business logic with the checking of parameters.
    Even if it comes to the same result, it would visualy look different and help the reading of the code if that is the goal.

  • Cole Markham
    Posted at 5:15 pm, June 6, 2012

    I’ve often used org.eclipse.core.runtime.Assert to do the same thing. It has an isNotNull method as well. I don’t really see the advantage of throwing IllegalArgumentException rather than NPE as long as you get some message other than ‘null’. If you’re catching IAE in client code that just seems like bad design, so either way it’s just some unchecked exception that will get trapped higher up the stack. The Eclipse Assert methods throw a custom AssertionFailedException for isNotNull and isTrue or IllegalArgumentException for isLegal, that seems logical to me.

  • Jens v.P.
    Posted at 5:26 pm, June 6, 2012

    What would uncle Bob say: “In most programming languages there is no good way to deal with a null that is passed by a caller accidentally. Because this is the case, the rational approach is to forbid passing null by default. When you do, you can code with the knowledge that a null in an argument list is an indication of a problem, and end up with far fewer careless mistakes.” [Robert C. Martin: Clean Code]. I always used to check parameters (as in your first example), I even have written some Eclipse templates for that. But after reading Clean Code, I probably won’t do that anymore, and instead simply assume all parameters to be non-null. An NPE is thrown anyway, sooner or later. And in most situations, there is not much difference between an NPE and an IllegalArgumentException, is there? Besides, I will follow the rule to not use null if possible, e.g., by returning empty collections.

    I’m also thinking about using Annotation, because of Stephan’s blog post: http://blog.objectteams.org/2012/02/help-the-jdt-compiler-helping-you-3-the-essence-of-null-annotations/. IMHO that’s really cool and it seems to be a good way to deal with the problem, at least to me.

    But I also will have a look at Guava. The cleaner the better 🙂

  • Thomas Ferris Nicolaisen
    Posted at 5:59 pm, June 6, 2012

    Great little article. I’ve added it to the collection here: http://www.tfnico.com/presentations/google-guava

  • Gabriel
    Posted at 3:47 pm, June 7, 2012

    I like this idea of using an easy to remember method against an if-then-throw-exception idiom, however it feels unnatural to logically *negate* all conditions you used before (and it is error prone if updating old code).

    I’d like to se methods like rejectArgument(boolean,String), rejectState(), and rejectXXXXX, to maintain the SAME condition as before.

  • Mark
    Posted at 4:09 pm, June 7, 2012

    Holger,
    Yeah, my comment was just “thinking out loud”. I am not sure there is any good solution. I was thinking the same thing about AOP. I did some digging and found some options but not sure how much better they are.
    The reason I responded was because i recently did a code review in which the first 10 (give or take) where just checking the parameters. The code obfuscated the actual business logic. And honestly, most of the time there would be an error and stacktrace anyway telling you where and what the error was. In addition to that he had unit tests to ensure the methods threw all of the [runtime] errors for parameter checking. Typically these errors will be design (development) time and not run time. I think the better way would be to design your API so that you have overloaded methods – See Martin Fowlers “Refactoring”, page 285. Of course, sometimes you DO need to check parameters and then you should. 🙂

  • Mark
    Posted at 5:56 pm, June 8, 2012

    Holger, I can see the need for better information if the user of the API does not have the source. What i would liked to see in code though would be:

    public void doSomething( List list ) {
    validateParameters(list);
    doSomethingMore();
    }

    I too think this discussion is great. I think it shows there is no easy answer and that we need to think about things. Not just randomly apply patterns based on what we think we know or read (which was the case of the developer that I mentioned). Now if someone would recreate Guava in .NET….