22

I've got an arrayList filled with elements. I would like to pass the elements of that array list as arguments to a variadic function.

My function

public SequenceEntityModifier(final IEntityModifier... pEntityModifiers)

My ArrayList

ArrayList<IEntityModifier> arr = new ArrayList<IEntityModifier>();
arr.add(new MoveXModifier(1, 50, 120));
arr.add(new MoveXModifier(1, 120, 50));

I'd like to pass it to the function as if I would pass them individually.

new SequenceEntityModifier( /* elements of arr here */ );

Is something like this possible?

Thanks in advance.

Alexey
  • 714
  • 8
  • 21
pad
  • 237
  • 2
  • 5

3 Answers3

25

Just do:

new SequenceEntityModifier(arr.toArray(new IEntityModifier[arr.size()]));

This copies the ArrayList to the given array and returns it. All vararg functions can also take arrays for the argument, so for:

public void doSomething(Object... objs)

All the legal calls are:

doSomething(); // Empty array
doSomething(obj1); // One element
doSomething(obj1, obj2); // Two elements
doSomething(new Object[] { obj1, obj2 }); // Two elements, but passed as array

One caveat:

Vararg calls involving primitive arrays don't work as you would expect. For example:

public static void doSomething(Object... objs) {
    for (Object obj : objs) {
        System.out.println(obj);
    }
}

public static void main(String[] args) {
    int[] intArray = {1, 2, 3};
    doSomething(intArray);
}

One might expect this to print 1, 2, and 3, on separate lines. Instead, it prints something like [I@1242719c (the default toString result for an int[]). This is because it's ultimately creating an Object[] with one element, which is our int[], e.g.:

// Basically what the code above was doing
Object[] objs = new Object[] { intArray };

Same goes for double[], char[], and other primitive array types. Note that this can be fixed simply by changing the type of intArray to Integer[]. This may not be simple if you're working with an existing array since you cannot cast an int[] directly to an Integer[] (see this question, I'm particularly fond of the ArrayUtils.toObject methods from Apache Commons Lang).

Community
  • 1
  • 1
Brian
  • 16,069
  • 5
  • 38
  • 64
  • 1
    Correct, ofc, but every time I write something like this I cringe - such a syntactic tangle. – Steve B. Sep 21 '12 at 16:47
  • @SteveB. I agree, overloading is a much better option than forcing this kind of method call, then convert behind the scenes. While varargs are nice, they don't play well with collections. – Brian Sep 21 '12 at 16:56
  • Not just a tangle; a performance hit with all the unnecessary (pointer) copying. See my answer below for a cheaper way. – Judge Mental Dec 07 '16 at 20:41
3

The construct IEntityModifier... is syntactic sugar for IEntityModifier[]

See the appropriate JLS section (8.4.1 Formal Parameters)

Brian Agnew
  • 254,044
  • 36
  • 316
  • 423
3

I always create an overload that takes Iterable< ? extends IEntityModifier >, and make the variadic version forward to this one using Arrays.asList(), which is cheap.

Judge Mental
  • 5,091
  • 15
  • 20