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:
checkArgumentthrowsIllegalArgumentExceptioncheckStatethrowsIllegalStateExceptioncheckNotNullthrowsNullPointerExceptioncheckElementIndexandcheckPositionIndexthrowIndexOutOfBoundsException, 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.
Nice summary. Definitely helps decide what to use.
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.
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!
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.
Nice summary and comparison of the two libraries. *Thumbs up*
Nice writeup…thanks!
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);
I think it’s cool that things like checkNotNull return the instance you’re checking for fluent usage:
getPeople(checkNotNull(personID));
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!
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.
Matt, it’s good to know about these improvements in beta version of Apache Commons!
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());
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.
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.
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.
Nice post. Thanks.
Did you check OVal (http://oval.sourceforge.net/)? You can do it using annotations.
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).
I haven’t seen OVal yet. Thanks for the link!
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.
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.
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?
I think that main benefit is readability. For me additional imports statements are not a big deal. My IDE handles them pretty well.
Neat! Added it to my growing list of Google Guava resources.
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!).
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.
Saso,
Perhaps the word requires is too strong. But IMO
Validate.isTruelooks nicer thanPreconditions.checkArgumentbecause it reads more like a sentence in natural language. Just curious, why do you prefer not to use static imports?(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.
(I did end up here because of a Guava issue though, so clearly I’m a fan of that too!)
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?
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-Checkand the other similar classes: http://qualitycheck.sourceforge.net/comparison.htmlPS: Of course, it is free software.