Java unpacking argument lists

12,543

Solution 1

public void printStrings(String... strings)
{
   // the strings parameter is really a String[].
   // You could do anything to it that you normally
   // do with an array.
   for(String s : strings){
      System.out.println(s);
   }
}

Can be called like this:

String[] stringArray = new String[10];
for(int i=0; i < stringArray.length; i++){
   stringArray[i] = "String number " + (i+1);
}

printStrings(stringArray);

The ... syntax is really syntactic sugar for arrays.

Java doesn't have the facility that you describe, but you could fake it several ways.

I think the closest approximation means overloading any function that you want to use in that fashion using varargs.

If you have some method:

public void foo(int a, String b, Widget c) { ... }

You can overload it:

public void foo(Object... args) {
    foo((Integer)args[0], (String)args[1], (Widget)args[2]);
}

But this is really clumsy and error prone and hard to maintain.

More generically, you could use reflection to call any method using any arguments, but it's got a ton of pitfalls, too. Here's a buggy, incomplete example of how it gets ugly really fast:

public void call(Object targetInstance, String methodName, Object... args) {
    Class<?>[] pTypes = new Class<?>[args.length];
    for(int i=0; i < args.length; i++) {
        pTypes[i] = args[i].getClass();
    }
    Method targetMethod = targetInstance.getClass()
              .getMethod(methodName, pTypes);
    targetMethod.invoke(targetInstance, args);
}

Solution 2

If the function you're calling is not a varargs function (declared with ...) then you do need to use reflection. Method.invoke() takes an array Object[] of arguments.

The tough part via reflection is finding the right method (well, it's easy if there's only one method with the same name, otherwise it's very difficult).

The cost is the extra time to lookup/invoke the method.


Of course, if you know the specific method at compile-time, then you can deal with this manually, e.g. here for a 3-argument function:

Object[] args = /* get args from somewhere */
callSomeNonVarargsFunction((Cast1)args[0], (Cast1)args[1], (Cast1)args[2]);
Share:
12,543

Related videos on Youtube

Kevin
Author by

Kevin

Updated on June 01, 2022

Comments

  • Kevin
    Kevin almost 2 years

    Here's another question of "How would I do this in Java?" In Python, I can use the '*' symbol to unpack arguments like so:

    >>> range(3, 6)             # normal call with separate arguments
    [3, 4, 5]
    >>> args = [3, 6]
    >>> range(*args)            # call with arguments unpacked from a list
    [3, 4, 5]
    

    Java supports getting a list of args with ...args syntax, but is there a way (perhaps using the Reflection libraries?) to unpack those for some other function?

    • Kaj
      Kaj almost 13 years
      Can you explain what the python code does?
    • Kevin
      Kevin almost 13 years
      @Kaj Sure. range() is a Python function that takes two integer arguments and produces an array of each integer between them, excluding the upper bound. The *args syntax takes the already-defined array args and expands / unpacks it into two distinct function arguments. It's like calling range(args[0], args[1]).
  • Oliver Charlesworth
    Oliver Charlesworth almost 13 years
    Indeed, but the OP is interested on whether you can do this for non-variadic methods.
  • Jonathon Faust
    Jonathon Faust almost 13 years
    @Oli what do you mean? It's not clear what he means by "unpack those for some other function."
  • Oliver Charlesworth
    Oliver Charlesworth almost 13 years
    I believe he means "is there a way to programatically access (e.g. iterate over) the parameter values for the current method?"
  • Oliver Charlesworth
    Oliver Charlesworth almost 13 years
    I don't think this is what the OP means. I believe he wants to be able to programatically access the arguments for the current method.
  • Jonathon Faust
    Jonathon Faust almost 13 years
    @Oli hmm...wouldn't that just be by name?
  • Oliver Charlesworth
    Oliver Charlesworth almost 13 years
    In a generic sense. i.e. some construct that will always give you args[], where args[0] refers to the first argument of the method, etc.
  • Admin
    Admin about 5 years
    That "the ... syntax is really syntactic sugar for arrays" isn't really relevant -- the Python * syntax that OP's drawing a comparison to is also 'really syntactic sugar for tuples.' The meat of the question is just whether it's possible to unpack an iterable in Java