I love varargs. For a long time, it was on my list of features from C++ that I wish Java had. I feel it makes array or list based API's a lot cleaner and easier to work with. Java 5 made me happy.
So now I find myself defensively coding around zero-length vararg parameters... for instance, if your method accepts varargs as an argument, then it's still possible to pass in nothing. This isn't always what I want. Sometimes I want a method to accept 1 or more arguments, not zero or more. Consider a method that prints out a variable number of Strings to the console:
void foo(String... parms) {
if (parms.length == 0) throw new IllegalArgumentException("parms: none");
for (String s : parms) {
System.out.print(s);
}
}
The point of the guard clause is to make sure (at run-time) that no one tries to pass you an empty list of parameters. This prints out Hello World.foo("Hello ", "World", ".");
but this throws an exception while compiling just fine:foo(); // this throws IllegalArgumentException
A nifty alternative is to declare the first element as required while allowing zero or more additional parameters:void foo(String first, String... others) {
System.out.print(first);
for (String s : others) {
System.out.print(s);
}
}
Now it is impossible to invoke the method with no arguments:foo(); // this won't compile
foo("Hello ", "World"); // but this will
If you're going to use a language with a compile-time type checker then it makes sense to have that mechanism do as much of the correctness verification as is possible. I've found this idiom of ensuring that at least one parameter is specified to be useful. The method implementation becomes a little more complex but the benefit is having the contract of the method declared and enforced by the compiler rather than burying that information in the documentation somewhere (or unit-test for that matter).
1 comment:
Heh. This reminds me of my old Perl-prototyping days (I've been pro-type checking, even in runtime-only languages, for a long time): a signature of sub($@) was often used for the same purpose. And, even in a runtime language, it caught bugs, which was useful even if it waited to catch those bugs until your users are actually beating on your code.
Keep in mind that you can have a private method which is simply foo(String... args), and then delegate handling directly to there. That gives you the compile-time safety with the run-time simplicity of implementation.
Post a Comment