Java Secret: More uses for varargs

Overview

Varargs have many uses from simplifying code. However, they are not always used as often as they could be.



Use in reflections

Calling a method via reflections is fairly ugly without varargs.

ClassLoader cl = Thread.currentThread().getContextClassLoader();
Method defineClass = cl.getClass().getDeclaredMethod("defineClass", 
    new Class[] { String.class, byte[].class, int.class, int.class});
defineClass.setAccessible(true);
defineClass.invoke(cl, 
    new Object[] { myNewClassName, myByteCode, 0, myByteCode.length });

With varargs, the code appears cleaner.
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Method defineClass = cl.getClass().getDeclaredMethod(
    "defineClass", String.class, byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(cl, myNewClassName, myByteCode, 0, myByteCode.length);

Use of varargs for optional arguments

System.out.printf use varargs which might be optional.
System.out.printf("Hello%n"); // no args to the varargs.
System.out.printf("Hello %s%n", name); // one argument to the varargs.
System.out.printf("Hello %s you are %d years old.%n", name, age); // two arguments

When varargs must have a minimum of one entry

The minimum number of entries for a varargs is 0, so if you need to have at least 1, you can add a parameter.
public static int average(int num, int... nums) {
    long total = num;
    for(int n: nums) total += n;
    return total/(nums.length+1);
}
This method will fail at runtime when no arguments are provided.
int a = average(); // fails to compile, instead of failing at runtime.

Use of varargs to build a List

A commonly used method is Arrays.asList(T...) The first example uses a varargs to build an array, the second example takes and array and passes it one as expected.
List<Integer> ints = Arrays.asList(1,2,3,4,5);
List<String> strings = Arrays.asList("one,two,three,four,five".split(","));

Use of varargs to build a Map

You can also use varargs to help build a map.
public static <K, V> Map<K, V> mapOf(K key, V value, Object... alteratingsKeysAndValues) {
    Map<K, V> map = new LinkedHashMap<K, V>();
    map.put(key, value);
    for(int i = 0; i < alteratingsKeysAndValues.length; i += 2)
        map.put((K) alteratingsKeysAndValues[i], 
                (V) alteratingsKeysAndValues[i+1]);
    return map;
}

Map<String, Integer> smallNumbers = mapOf("zero", 0, "one", 1, "two", 2);

Comments

  1. So, we are using Java 5 varargs but not Java 5 generic Lists and Maps? Not worth the cost. I would rather have strongly types containers with a little more init code than the opposite.

    ReplyDelete
  2. @Greg, I agree that using generics is best practice. Unfortunately I forgot that this blog treats generics types as HTML. ;)

    ReplyDelete
  3. Practical hints. Lists and Maps constructors are implemented conveniently in Google Guava.

    ReplyDelete
  4. And Google Guava is type safe (generics) as well.

    ReplyDelete
  5. Nice article.

    Unfortunately the last example with a map is not a good way of coding. You'll easy can get it work wrong with ClassCastException. So, I wouldn't pass it on code review ;)

    ReplyDelete
  6. SLF4J could make use of varargs:

    logger.debug("{},{},{},{}",1,2,3,4);

    ReplyDelete
  7. @Stjepan, It could use varargs to simplify the code. However with debug messages, there can be alot of them and they may not be enabled. i.e. you want them to have as little performance impact as possible. Unfortunately varargs creates an object even if it is immediately discarded.

    ReplyDelete
  8. @1ndigo, The last example is typically used to build a static collection, i.e. if it works the first time it is used e.g. in a unit test, it will continue to run correctly.

    There are many ways to meaningfully validate a system before it is deployed.

    ReplyDelete
  9. Variable argument is indeed a very interesting feature but still under utilized. you know even main method is written using varargs. by the way I also blogged my experience as variable arguments in java let me know how do you find it

    ReplyDelete

Post a Comment

Popular posts from this blog

Low Latency Microservices, A Retrospective

Unusual Java: StackTrace Extends Throwable

System wide unique nanosecond timestamps