Reputation: 5220
Do you know some nice alternative to Apache Commons Validate or Guava Preconditions that would throw IllegalArgumentException instead of NullPointerException when checking if object is not null (except Spring Assert)?
I'm aware that Javadocs say:
Applications should throw instances of this class [NullPointerException] to indicate other illegal uses of the null object.
Nevertheless, I just don't like it. For me NPE was always meaning I just forgot to secure null reference somewhere. My eyes are so trained, I could spot it browsing logs with a speed of few pages per second and if I do there is always bug alert in my head enabled. Therefore, it would be quite confusing for me to have it thrown where I expect an IllegalArgumentException.
Say I have a bean:
public class Person {
private String name;
private String phone;
//....
}
and a service method:
public void call(Person person) {
//assert person.getPhone() != null
//....
}
In some context it may be ok, that a person has no phone (my grandma doesn't own any). But if you'd like to call such person, for me it's calling the call method with an IllegalArgument passed. Look at the hierarchy - NullPointerException is not even a subclass of IllegalArgumentException. It basically tells you - Again you tried to call a getter on null reference.
Besides, there were discussions already and there is this nice answer I fully support. So my question is just - do I need to do ugly things like this:
Validate.isTrue(person.getPhone() != null, "Can't call a person that hasn't got a phone");
to have it my way, or is there a library that would just throw IllegalArgumentException for a notNull check?
Upvotes: 7
Views: 7822
Reputation: 90023
Take a look at https://github.com/cowwoc/requirements.java/ (I'm the author). You can override the default exception type using withException()
as follows:
new Verifiers().withException(IllegalArgumentException.class).requireThat(name, value).isNotNull();
Upvotes: 1
Reputation: 7695
What about Preconditions
's checkArgument
?
public void call(Person person) {
Preconditions.checkArgument(person.getPhone() != null);
// cally things...
}
checkArgument
throws
IllegalArgumentException
instead of NullPointerException
.
Upvotes: 5
Reputation: 4581
You can use valid4j with hamcrest-matchers (found on Maven Central as org.valid4j:valid4j). The 'Validation' class has support for regular input validation (i.e. throwing recoverable exceptions):
import static org.valid4j.Validation.*;
validate(argument, isValid(), otherwiseThrowing(InvalidException.class));
Links:
On a side-note: This library also has support for pre- and post-conditions (like assertions really), and it's possible to register your own customized global policy, if needed:
import static org.valid4j.Assertive.*;
require(x, greaterThan(0)); // throws RequireViolation extends AssertionError
...
ensure(r, notNullValue()); // throws EnsureViolation extends AssertionError
Upvotes: 1
Reputation: 11870
Since the topic of this question evolved into "Correct usage of IllegalArgumentException and NullpointerException", I would like to point out the strait forward answer in Effective Java Item 60 (second edition):
Arguably, all erroneous method invocations boil down to an illegal argument or illegal state, but other exceptions are standardly used for certain kinds of illegal arguments and states. If a caller passes null in some parameter for which null values are prohibited, convention dictates that NullPointerException be thrown rather than IllegalArgumentException. Similarly, if a caller passes an out-ofrange value in a parameter representing an index into a sequence, IndexOutOfBoundsException should be thrown rather than IllegalArgumentException.
Upvotes: 8
Reputation: 5220
I guess I learned something again here on SO thanks to great comments by Olivier Grégoire, Louis Wasserman, CollinD and Captain Man. The standards are ussually a strong and sufficient reason as they make the common language programmers will always understand correctly, but in this particular case I had this little doubt, that maybe this rule set around NPE isn't too ok. Java is an old language and some of its features came up to be a bit unlucky (I don't want to say wrong, that's maybe too strong judgment) - like checked exceptions, although you may also disagree. Now I think that this doubt is resolved and I should:
public void call(Person person)
I know what does it mean to the system that the phone number is null.Having above in mind I would say the best option to make the assertion in the public void call(Person person)
example is like Captain Man suggests:
Preconditions.checkArgument(person.getPhone() != null, "msg");
Check argument is a good name for this method - it's clear that I'm checking the business contract compliance against the person argument and it's clear that I'm expecting IllegalArgumentException if it fails. It's a better name than the Validate.isTrue of Apache Commons. Saying Validate.notNull or Preconditions.checkNotNull on the other hand suggest that I'm checking for a null reference and I'm actually expecting the NPE.
So the final answer would be - there is no such nice library and shouldn't be as this would be confusing. (And Spring Assert should be corrected).
Upvotes: 0
Reputation: 23858
Not that I'm aware of. I'd just roll your own to get the behavior you want with a concise invocation, mimicking Guava's implementation but tweaking the exception type.
class Preconditionz {
public static <T> T checkNotNull(T reference, Object errorMessage) {
if (reference == null) {
throw new IllegalArgumentException(String.valueOf(errorMessage));
}
return reference;
}
}
I like to go ahead and import static
these really frequently used methods, too, so you can call them super concisely.
import static com.whatever.util.Preconditionz.checkNotNull;
// ...
public void call(Person person) {
checkNotNull(person, "person");
checkNotNull(person.getPhone(), "person.phone");
// ...
}
Depending on your environment, you might want to name it checkNotNull2
so it's easier to add the import via autocompletion in your IDE, or let you use it alongside the standard checkNotNull
.
Upvotes: 0
Reputation: 757
You can easily do this:
if (person.getPhone() == null) {
throw new IllegalArgumentException("Can't call a person that hasn't got a phone");
}
It is clear to other programmers what you mean, and does exactly what you want.
Upvotes: -1