In our article API Change that breaks at Runtime we discussed an API change in our smartics-commons library. We introduced a new class called Arg that allows to check method arguments. It has a slight improvement for its usability compared to the old Arguments class.

This post will show you the actual API change in action.

Failing fast

To follow the path of fail-fast a method should check its arguments prior to actually using it. This allows to spot the source of the problem quickly. In Design-by-Contract this is a precondition to be met before the execution of some code starts.

 

For a detailed discussion of the topic of checking preconditions in Java, I recommend reading Joshua Bloch’s article: Check parameters for validity.

This is how an argument check in Java looks like:

public void add(final Item item) {
  if(item == null) {
    throw new NullPointerException("item must not be 'null'!");
  }
  
  items.add(item);      
}

Preferable would be to make this check in a single line like this:

public void add(final Item item) {
  Arg.checkNotNull("item", item);
    
  items.add(item);      
}

Arg allows to write the check in one line instead of three. A more compact representation that is easier to read.

Exception in ... 
  de.smartics.util.lang.NullArgumentException: item must not be 'null'.
	at de.smartics.util.lang.Arg.checkNotNull(Arg.java:87)
	at de.smartics.util.lang.Arg.checkNotNull(Arg.java:64)
        ...

This way the error message also adheres to the same wording for each raised exception.

It also states the problem more clearly than if the code just runs into a NullPointerException:

Exception in thread "main" java.lang.NullPointerException
	at MyClass.add(MyClass.java:29)
	at Somewhere.something(Somewhere.java:42)
        ...

That’s why the method requires the name of the argument to be passed as the first argument. If you do not feel comfortable with that, have a look at one of the following alternatives:

  1. Java 7: Objects
  2. Apache commons-lang: Validate
  3. Google guava-libraries: Preconditions

Apache’s and Google’s version provide much more methods on checking values than our class does, but they all three either provides a generic message or you have to pass in the message you want to be displayed in case of detecting an illegal argument.

NullPointerException or IllegalArgumentException?

Due to Java conventions the exception de.smartics.util.lang.NullArgumentException does not derive from IllegalArgumentException as one might expect.

If a caller passes null in some parameter for which null values are prohibited, convention dictates that NullPointerException be thrown rather than IllegalArgumentException.

Joshua Bloch. Effective Java – Second Edition, p. 248

So we should follow this convention. For more information on this topic please refer to this mailing list posting: commons lang3: NullArgumentException missing?

Declare raised Exception

There is a discussion (e.g. at stackoverflow) whether or not runtime exceptions should be declared. For me, as an API user, declaring the raised exception helps to know how to use a particular piece of an API.

/**
 * ...
 *
 * @param item the item to add to the list of items.
 * @throws NullPointerException if {@code item} is {@code null}.
 */
public void add(final Item item) throws NullPointerException {
  Arg.checkNotNull("item", item);
  
  items.add(item);      
}

This clearly shows that passing a null value for an item is not allowed.

 

Please note that we declare a NullPointerException instead of a NullArgumentException. This is because the NullPointerException is a basic, well-known exception of Java and we do not want to expose exceptions of third-pary libraries (like smartics-commons) in APIs.

Blank Strings considered

Besides checks for illegal null arguments we often check for String instances to be not blank, i.e. not null, not empty, and not only containing whitespaces.

public void doSomething(final String input)
  throws NullPointerException, IllegalArgumentException {
  Arg.checkNotBlank("input", input);
 
  ...
}

And there is a special version if you allow a value to be null, but not empty or only containing whitespaces.

Arg.checkNotBlankExceptNull("input", input);

Constructors

The technique of failing-fast is especially useful on construction of an instance of a class. This is because a failure may be encountered much later than when the bug was introduced.

public Item(final String name) {
  this.name = Arg.checkNotBlank(name);
}
 
public int displayWidth() {
  return name.length(); //  <-- problem if not checked at construction time
}

This short version is possible since the release of version 0.4.0. Prior to that we had to use two lines of code, instead of one.

public Item(final String name) {
  Arguments.checkNotBlank(name);
  this.name = name;
}

Conclusion

This has been a short information on checking preconditions with Arg with references to interesting articles and posts to this topic on the web.

For more information on our small Java library, please refer to smartics-commons or directly to the project’s site.


Link

Link

Posts

Tagcloud

Loading tagcloud ...