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!