Avoiding Java varargs snafus

Since Java 1.5, Java has allowed you to take advantage of “varargs“, a usability feature that many other languages support. It lets you write really clean code and support some pretty cool use cases.

However, there is at least one possible pitfall of using varargs. Consider the method below:


public boolean filter() {
(do some filtering)
}

filter();

Let’s say you factor the existing filtering logic out into a FilterStrategy class, and change the method to take an array of FilterStrategy objects using varargs syntax so that it looks like this instead:


public boolean filter(FilterStrategy... strategies) {
for (FilterStrategy: strategies) {
(use the strategies)
}
}

filter();

The interesting thing to take note of is that your refactoring actually didn’t break any of the callers – it just silently turned them into no-ops. This is because, as the docs say, varargs “automates and hides the process” of passing an array. Putting no arguments in a call to filter is the same as


filter(new FilterStrategy[0]);

In some cases, this may be what you want. However, in the case we described above, it’s certainly not – it’s hard to imagine a filter method where not filtering anything is the common case.

The problem here arises from the misuse of varargs. Using varargs basically means “zero or more”, when in fact this method is looking for “one or more”. However, nothing in the method signature is actually enforcing this. Luckily, in cases like this, there is an easy solution:


public boolean filter(FilterStrategy first, FilterStrategy... rest) {
// use first
(...)
// use rest
for (FilterStrategy: rest) {
(...)
}
}

// this will be a compile error
filter();

Now, after the refactoring, the compiler will tell you that you’ve made an error in calling the filter method.

Finally, it’s worth noting that another way to avoid problems like this is to just not use varargs at all when they don’t make sense. I know that I personally have used varargs in the past when I knew the production code would be using an array, but the testing code would like to just pass one or two of something. This is probably a significant misuse of the construct for very little usability gain, so I would discourage others from going down the same road. (You can usually approximate the same effect with Arrays.asList anyways.)

  • Facebook
  • HackerNews
  • Reddit
  • Twitter
  • del.icio.us
  • Digg
  • Slashdot
  • StumbleUpon

Follow Bryan on Twitter: @bryanduxbury

This entry was posted in Miscellaneous and tagged . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

One Comment

  1. George
    Posted February 10, 2011 at 1:46 am | Permalink

    Thank you for this nice and quick trick…

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

  • Rapleaf Is Hiring!

    We are looking for engineers who want to solve challenging problems.

    We have great people, do great work, and have great perks.

    Know someone who might be interested? Refer a friend and get $5,000 for successful hires.

    See our current openings at
    www.rapleaf.com/careers