Google Guava vs Apache Commons for Argument Validation

It is an established good practice to validate method arguments at the beginning of the method body. For example you could check that the passed value is not negative before doing some calculation:

public int doSomeCalculation(int value) {
    if (value < 0) {
        throw new IllegalArgumentException("negative value");
    }
    ...
}

It can be written slightly shorter using the good old Apache Commons:

Validate.isTrue(value >= 0, "negative value");

More recently the same behavior can be achieved with Google Guava after statically importing the Preconditions class:

checkArgument(value >= 0, "negative value");

At surface it looks quite similar but usually the devil is in the details so I decided to take a closer look at both approaches. In this post I’m going to describe the differences between the two libraries regarding argument validation.

Static imports

The first immediately obvious difference is that Guava requires static import to look nice. Validate.isTrue() looks better than Preconditions.checkArgument(). Personally, I don’t mind static imports in my code. For some people it might be a small disadvantage though. Especially for those who don’t know how to work with them in the IDE yet. Also, if you work on some ancient project that still uses Java earlier than 5.0 you won’t be able to use Guava at all.

Types of exceptions

All methods from Validate class in Apache Commons throw IllegalArgumentException when validation fails. Sometimes it make sense to throw a different exception type. Guava make it possible. For example:

  • checkArgument throws IllegalArgumentException
  • checkState throws IllegalStateException
  • checkNotNull throws NullPointerException
  • checkElementIndex and checkPositionIndex throw IndexOutOfBoundsException, etc.

It’s obvious from the method name what exception gets thrown. I like this clear distinction in Guava.

Message parameters

It’s a good idea to give as much information about the failure as possible. For example if you validate that a number is positive you should add the actual number in the exception message if it’s not. In the example below it is done using the string concatenation directly:

Validate.isTrue(i > 0, "Should be positive but was: " + i);

In Commons Validate.isTrue() method you can pass additional parameter instead. It offers a performance benefit because the string concatenation is actually done only when the validation fails.

Validate.isTrue(i > 0, "Should be positive but was: ", i);

You can do a similar thing in Guava:

checkArgument(i > 0, "Should be positive but was: %s", i);

Additionally, Guava uses varargs for message parameters and you could also write:

checkArgument(i > MIN, "Expected more than %s, got %s", MIN, i);

In this case it’s also more readable than using string concatenation:

checkArgument(i > MIN, "Expected more than " + MIN + ", got " + i);

Validating collections and arrays

Apache Commons has some additional validations for collection and arrays that you won’t find in Guava:

  • allElementsOfType(Collection collection, Class clazz)
  • Validate.notEmpty(Collection collection)
  • Validate.notEmpty(Map map)
  • Validate.notEmpty(Object[] array)
  • Validate.noNullElements(Collection collection)
  • Validate.noNullElements(Object[] array)

This first one might be handy in legacy project not using generics. Others are generally useful.

On the other hand you can combine Guava Preconditions with any utility methods. In the example below I use the isNotEmpty method from Commons CollectionUtils in conjunction with Guava Preconditions to ensure that the list is not null and not empty:

checkArgument(isNotEmpty(list));

Assignment after validation

It’s common to assign a method argument to a field after validation. For example with Validate from Apache Commons you could write:

public Class(Object parameter) {
    Validate.notNull(parameter);
    this.field = parameter;
}

The checkNotNull from Guava Preconditions returns the validated reference. This allows validation and assignment in one line:

public Class(Object parameter) {
    this.field = checkNotNull(parameter);
}

Summary

In summary, here are the main advantages of both classes:

Apache Commons Validate

  • Works in old versions of Java
  • Readable without static imports
  • Collection and array validations

Google Guava Preconditions

  • Additional exception types
  • Better handling of message arguments
  • Easy assignment after not null check

Verdict

I prefer Guava Preconditions over Commons Validate for argument validation.

Share
This entry was posted in Java and tagged , , , , . Bookmark the permalink.

31 Responses to Google Guava vs Apache Commons for Argument Validation

  1. Nice summary. Definitely helps decide what to use.

  2. Jed Wesley-Smith says:

    The Validate version example with parameters does concatenation on the message on every call. This is very expensive and should be avoided as it is only needed in the exceptional case.

  3. So your point is that when I pass a parameter instead of using string concatenation directly it will actually concatenate the strings only when validation fails? It will surely have some impact on performance. I should have thought about that. I’ll definitely incorporate this into the post. Thanks a lot for this comment!

  4. Dave says:

    Yeah, this statement:

    “Should be positive but was: ” + i

    will do String concatenation immediately–there’s no delayed evaluation like in a Lisp macro. Whether or not it’s “very” expensive depends on how often it’s being called–string concatenation is nowhere near as expensive as it used to be.

  5. Jaran says:

    Nice summary and comparison of the two libraries. *Thumbs up*

  6. Dan Lewis says:

    Nice writeup…thanks!

  7. reisi says:

    Just in case you don’t have neither of these already in your classpath but you already have Spring (can’t remember in which module this is in) but it also has a class Assert (AFAIR under package org.springframework.util) containing many assertions for primitive, array and collection types.

    There is also an Assert#state(boolean) for your IllegalStateException needs.

    Perhaps we should come up with an asserter that will support building the message a bit like SLF4J:

    Assert.state(i == 1, “Illegal state; expected {} but was {}”, 1, i);

    So the method would be:

    public static void state(boolean state, String msg, Object… values);

  8. Squirrels says:

    I think it’s cool that things like checkNotNull return the instance you’re checking for fluent usage:
    getPeople(checkNotNull(personID));

  9. Matt Benson says:

    Note that the recently released commons-lang3 3.0-beta defers all argument handling and returns validated arguments where sensible. That eliminates two of your three stated reasons to prefer Guava, by my count. Thanks for the article!

  10. Matt Benson says:

    I’d amend my previous comment with the detail that oac.lang3.Validate now supports varargs-specified message arguments in addition to the other details already mentioned. I’m pretty sure the comment in the thread about deferred argument handling was more an indictment of the original example; without having checked, I’d be reasonably sure [lang] was already properly deferring concatenation of messages with arguments. And like Guava, [lang] Validate is now deferring those to String.format() for printf-style substitution.

  11. Matt, it’s good to know about these improvements in beta version of Apache Commons!

  12. Christian says:

    I find the commons validation methods a bit too specific, they somehow reminds me of the countless PHP functions, duplicating functionality only for the sake of beeing case insensitive.

    There is also no need to write a method like isNotEmpty(list). The Java API has all you need:
    checkArgument(!list.isEmpty());

  13. Christian, the difference is that when the list is null it will throw NullPointerException, not IllegalArgumentException. Also, if you specify a message as a parameter of the checkArgument method it will not be displayed.

  14. Colin Decker says:

    I’m in agreement with Christian. Many of the methods in the Apache Commons Validate class are unnecessary and distracting… it’s a problem I have with all of the Apache Commons stuff I’ve looked at in comparison to Guava. There are just too many methods that aren’t really needed. Guava boils things down to the essentials.

    As far as checkArgument(!list.isEmpty()) throwing NPE when the list is null… arguably that’s exactly what should happen! Do you really want an IllegalArgumentException that says “The validated collection is empty” or some such when the list is actually null? I don’t. I think there’s two camps on the issue of whether an IllegalArgumentException or a NPE should be thrown when an argument is null (I’m of the opinion it should be NPE), but at the very least a misleading message is the wrong way to go.

  15. I guess there are two camps. I don’t have a strong opinion on this. My point was that you can combine checkArgument with any utility method to accomplish the same thing as with additional methods in Commons. If you prefer IllegalArgumentException to be thrown in this case you can write checkArgument(isNotEmpty(list)). If you prefer NPE you can write checkArgument(!list.isEmpty()) as suggested by Christian. It’s completely up you.

  16. Rajesh says:

    Nice post. Thanks.

  17. iCesofT says:

    Did you check OVal (http://oval.sourceforge.net/)? You can do it using annotations.

  18. Christian says:

    Joshua Bloch suggests in “Effective Java” to throw exceptions that express as precisely as possible what happened. Especially he suggests to throw NullPointerExceptions when an argument is null (and shouldn’t be).

  19. I haven’t seen OVal yet. Thanks for the link!

  20. If Joshua Bloch suggests to throw NPE in this case it must be the right way to go! :-) Thanks, I didn’t remember this particular one from “Effective Java” despite reading it twice.

  21. Vitaly says:

    Christian, having notEmpty check of the collection in the Apache Common is normal in case your application logic consider null collection as empty too. If you need to throw NPE I believe this is better

    Validate.notNull(collection, “null collection is not allowed”);
    Validate.isTrue(!collection.isEmpty(), “empty collection is not allowed”);

    than

    Validate.isTrue(!collection.isEmpty(), “empty collection is not allowed”);

    last statement throws NPE without specific message which might be due to the developer mistake. So 1st option is much more readable and obvious. I am not in favour of doing such a shortcuts.

  22. EricB says:

    I’m still not clear…

    Why is adding an additional dependency on a third party framework better than basic if () throw logic?

    Seems the added imports and function calls prevents it from truly being shorter.

    Is it because it breaks out into predefined extended Exceptions?

  23. I think that main benefit is readability. For me additional imports statements are not a big deal. My IDE handles them pretty well.

  24. Charlie Collins says:

    Sorry for the late reply, I just stumbled on this article today.

    The reason it’s better to include such a library goes beyond just the “Preconditions/Validate” stuff. There are many more tremendously useful things in Guava, and it’s a relatively small library. If you JUST want the argument check, then you’d probably be better off to write your own small utility class to handle that (or copy just Preconditions).

    The big advantage for me with Guava in general, over Apache-Commons, is the support for generics, and the clean, precise APIs, without the proliferation of “what if” methods (already noted in several other comments), and how incredibly useful and powerful the Functions/Predicates/Collections stuff in there is.

    Combine Guava, with Guice, and JSR-305 annotations (@Nullable, etc), and you have a great minimalist Java SE stack that doesn’t have to suck (Java isn’t dead yet!).

  25. Saso says:

    Piotr,

    I don’t understand your statement about Guava requires static import. I actually prefer not to use static import, and Preconditions.checkArgument works just fine.

  26. Saso,

    Perhaps the word requires is too strong. But IMO Validate.isTrue looks nicer than Preconditions.checkArgument because it reads more like a sentence in natural language. Just curious, why do you prefer not to use static imports?

  27. Rich says:

    (Late to the party…)

    For commonly used validation I’d be more inclined to use JSR 303 (Bean Validation) for which the reference implementation is Hibernate Validator 4. It uses similar annotations to OVal … e.g. @NotNull and is a standard so various web, persistence, etc. frameworks can help maintain your validation requirements.

    Validation on method parameters (and return types) didn’t make it into that JSR, but there’s a pending JSR349 which is looking at adding it, and there’s an existing implementation in Hibernate Validator 4.2.

  28. Rich says:

    (I did end up here because of a Guava issue though, so clearly I’m a fan of that too!)

  29. Naveen says:

    I want to do something like this:

    checkNotNull(participantForExperiment, new ParticipantForExperimentNotFoundException(participantId, experimentId));

    Instead of using an IF condition to check whether participantForExperiment is null and then throw Exception, i want a one-liner in Guava like i mentioned above.

    But i want to throw my own exception instead of NullPointerException if it is Null.

    How can i do that in Guava?

  30. This is a very nice comparison between Validate and Preconditions.

    We are right now working on a similar project, Quality-Check, which has several advantages to Validate and Preconditions. Advantages include:
    - Readable without static imports (e.g. Check.notNull, Check.hasAnnotation, Check.notNaN)
    - Easy assignments after Checks (similar to Preconditions)
    - Small library which does _only_ checks, no need to include big framework for such checks
    - Special exceptions for every failed check to either distinguish failed checks from other errors
    - We include collection and array validation
    - Advanced validations like hasAnnotation, instanceOf
    - Mathematical Check (Check.notNaN, Check.isNumber)

    So, I think we combine advantages of both with several addons (e.g. our @ArgumentsChecked annotatioN).

    You can take a look on this page to find a comparison of Quality-Check and the other similar classes: http://qualitycheck.sourceforge.net/comparison.html

    PS: Of course, it is free software.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>