Last time we looked at how we could tidy up code that deals with a single, possibly-null varargs parameter. But of course there are lots of cases where the business rule is an "at-least-one" scenario.
An example of a real API that operates like this is the mighty Mockito's thenReturn method, which looks like this:
OngoingStubbing<T> thenReturn(T value, T... values)
Which is typically used to define mock behaviour like this:
Mockito.when(
mockCountdownAnnouncer.getCurrent()).thenReturn(
"Three", "Two", "One", "Liftoff");
The nice thing about this is the "fluent" way you can add or remove parameters from the list, and it just keeps working - as long as you've specified at-least-one return value.
This kind of API is really pleasant to use, but it'd be doubly great to have clean code within methods like this. The VarargIterator needs some extension!
/**
* @return an {@link Iterable} of a suitable type.
* Null-safe; passing a null {@code optionalArgs} will simply return
* a single-element {@code Iterable}.
* @throws IllegalArgumentException if {@code compulsoryArg} is null
*/
public static final <T> Iterable<T> forCompulsoryAndOptionalArgs(
final T compulsoryArg, final T... optionalArgs) {
Validate.notNull(compulsoryArg,
"the first argument to this method is compulsory");
if (optionalArgs == null) {
return Collections.singletonList(compulsoryArg);
} else {
List<T> iterable = new ArrayList<T>(optionalArgs.length + 1);
iterable.add(compulsoryArg);
iterable.addAll(Arrays.asList(optionalArgs));
return iterable;
}
}
As you can see, we encapsulate null-checking and null-safety in this method, allowing users to simply write (with a static import in this example):
public OngoingStubbing<T> thenReturn(T value, T... values) {
for (T retValue :forCompulsoryAndOptionalArgs(value, values)) {
// Do Mockito magic with each retValue
}
}
Mmmm. Squeaky-clean!