Javier Mr
Javier Mr

Reputation: 2210

How to unpack an array into different arguments on method call

I would like to know if it is possible to unpack an Object array into separate Object on method call which accepts vargs. This question is similar to this one.

I have a code like:

public class Test {
    public static Object doWork(Object... objects){
        System.out.println(objects.length);
        return objects;
    }

    public static void main(String[] args){
        Object res = doWork("one", "two");
        res = doWork("three", res);
    }
}

I would like to unpack the res object in the second call so it would receive an object array with length 3 instead of length 2 as now (where the second position is an Object array of length 2, having then all three arguments).

Is even that possible in Java?


More detailed:

By doing

Object res = doWork("one", "two");
res = doWork("three", res);

the second call gets called as:

doWork( Object[ "three", Object[ "one", "two" ] ] )

where i would like:

doWork(Object[ "one", "two", "three" ] )

I know this can be achieved by doing:

public static void main(String[] args){
res = doWork("one", "two");
    List<Object> los = Arrays.asList(res);
    los = new ArrayList<>(los);     // Can't modify an underlying array
    los.add("three");
    res = doWork(los.toArray());
}

But I'm looking for something like the unpack Lua built in function or the Python way described in the previously mentioned SO question.


Both answers given by @chancea and @Cyrille-ka are good and also solve the problem. One of the facts that might be a good idea to take into account is if the signature of the method can be modified. @cyrille-ka answer respects the function's signature, whereas @chancea does not. However I think in most cases one can just write asimple wrapper function to another one, so that shouldn't be a problem. On the other hand @chancea's way might be easier to use while programing (there no possible mistake of forgetting to call the unpack function).

Upvotes: 16

Views: 21590

Answers (3)

chancea
chancea

Reputation: 5968

This does not implement the Unpack solution, instead it goes about it by making an overload method as I said in my comment. I do not know if this at all what you wanted, but I got it to work and I felt like I would post this for reference.

public class Test {
    public static Object doWork(Object... objects){
        System.out.println(objects.length);
        return objects;
    }

    // this is the method that will concatenate the arrays for you
    public static Object doWork(Object[] objects1, Object... objects2){
        System.out.println(objects1.length + "+" + objects2.length);
        Object[] retval = new Object[objects1.length+objects2.length];
        System.arraycopy(objects1, 0, retval, 0, objects1.length);
        System.arraycopy(objects2, 0, retval, objects1.length, objects2.length);
        return retval;
    }

    public static void main(String[] args){
        Object res = doWork("one", "two");
        res = doWork((Object[])res, "three");
        Object[] res2 = (Object[])res; // = {one, two, three}
    }
}

Upvotes: 1

Cyrille Ka
Cyrille Ka

Reputation: 15533

Well, there is no syntactic sugar à la Python or Lua for that in Java, but you can create your own unpack method:

@SafeVarargs
public static <E> Object[] unpack(E... objects) {
    List<Object> list = new ArrayList<Object>();
    for (Object object : objects) {
        if (object instanceof Object[]) {
            list.addAll(Arrays.asList((Object[]) object));
        }
        else{
            list.add(object);
        }
    }

    return list.toArray(new Object[list.size()]);
}

This will returns an array containing all the input elements, unpacked.

Then you can call it in your main method:

res = doWork(unpack("three", res));

The reason I make this method generic is that you can call it with, for example, a String[] array, without generating a warning. For some reason, the Java compiler thinks that this method has a chance of "polluting the heap", but it is not the case, that's why I added a @SafeVarargs annotation.

Upvotes: 8

Viktor Mellgren
Viktor Mellgren

Reputation: 4506

Try to return as an array of Object instead. Then concatenate "three" at the end of the returned array.

Upvotes: 0

Related Questions