0

How do you pass an array of arguments, like python's f(*args)?

Exampes from other languages:

Python: f(*args)

JavaScript: f.apply(this, args)

Ruby: f(*args)

Similar to Can I pass an array as arguments to a method with variable arguments in Java? and varargs and the '...' argument, but the function declaration doesn't use spread syntax.

void draw(int x, int y) {
    ...
}

In addition, is this possible when the arguments are not all the same type?

void draw(int x, String y) {
    ...
}
Will
  • 1,171
  • 2
  • 14
  • 26
  • Anything—let's say an array of two numbers, where the function takes two int parameters – Will Feb 15 '18 at 22:07
  • Already noted in the description how this question is different. – Will Feb 15 '18 at 22:11
  • Don't understand the downvotes. Perfectly accurate question. If you downvote, please explain why. – Will Feb 15 '18 at 22:25
  • Possible duplicate of [Can I pass an array as arguments to a method with variable arguments in Java?](https://stackoverflow.com/questions/2925153/can-i-pass-an-array-as-arguments-to-a-method-with-variable-arguments-in-java) – Gergely Bacso Feb 15 '18 at 22:31
  • @GergelyBacso **Already noted in the description how this question is different.** – Will Feb 15 '18 at 22:31
  • Possible duplicate of [varargs and the '...' argument](https://stackoverflow.com/questions/1656901/varargs-and-the-argument) – mikep Feb 15 '18 at 23:36
  • Again, this is different because the method **declaration** doesn't use spread syntax. – Will Feb 15 '18 at 23:42
  • I'm confused, I think in Java the equivalent is the reflection API: https://stackoverflow.com/questions/13876300/java-reflection-passing-in-a-arraylist-as-argument-for-the-method-to-be-invoke – Lee Kowalkowski Feb 16 '18 at 01:02

4 Answers4

2

You can do this with reflection, but it's probably more performant to use cached method handles that you initialize once, then reuse as many times as you need.

class SpreadInvoker {
    public static void draw1(int x, String y) {
        System.out.printf("draw1(%s, %s)%n", x, y);
    }

    public void draw2(int x, int y) {
        System.out.printf("draw2(%s, %s)%n", x, y);
    }

    static MethodHandle DRAW1;
    static MethodHandle DRAW2;

    public static void main(String[] args) throws Throwable {
        DRAW1 = MethodHandles.lookup()
                             .findStatic(
                                 SpreadInvoker.class,
                                 "draw1",
                                 MethodType.methodType(
                                     void.class,
                                     int.class,
                                     String.class
                                 )
                             )
                             .asSpreader(Object[].class, 2);

        DRAW2 = MethodHandles.lookup()
                             .findVirtual(
                                 SpreadInvoker.class,
                                 "draw2",
                                 MethodType.methodType(
                                     void.class,
                                     int.class,
                                     int.class
                                 )
                             ).asSpreader(Object[].class, 2);

        SpreadInvoker instance = new SpreadInvoker();

        final Object[] args1 = { 13, "twenty-six" };
        final Object[] args2 = { 13, 26 };

        DRAW1.invoke(args1);           // SpreadInvoker.draw1(13, "twenty-six")
        DRAW2.invoke(instance, args2); // instance.draw2(13, 26)
    }
}

Output:

draw1(13, twenty-six)
draw2(13, 26)

Note, however, that this is the sort of thing you'd do if you don't know what method you need to call at compile time. This sort of thing should almost never be necessary.

Mike Strobel
  • 25,075
  • 57
  • 69
1

This style of calling methods is not usual for Java language, but possible with reflection API:

    Method drawMethod = YourClass.class.getDeclaredMethod("draw", new Class[] { int.class, int.class });
    drawMethod.invoke(null, (Object[]) args);

Further reading

Vasily Liaskovsky
  • 2,248
  • 1
  • 17
  • 32
  • `null` is eligible for first argument of `invoke` only if the method is declared static – Vasily Liaskovsky Feb 15 '18 at 22:17
  • Thank you! How would this be accomplished when the arguments are not all the same type? – Will Feb 15 '18 at 22:25
  • You should pass desired argument types as second argument to `getDeclaredMethod`. Obviously, this can only work if corresponding method is actually declared. – Vasily Liaskovsky Feb 15 '18 at 22:29
  • Oh great! Because Object[] can contain anything? – Will Feb 15 '18 at 22:30
  • Expected type of second argument of `invoke` is `Object[]`. Cast there is just for clarity. – Vasily Liaskovsky Feb 15 '18 at 22:32
  • Are you sure this works? I'm getting `error: unreported exception NoSuchMethodException; must be caught or declared to be thrown java.lang.reflect.Method solution = YourClass.class.getDeclaredMethod("draw", new Class[] { int.class, int.class });` for `class YourClass { public void draw(int x, int y) { // do nothing } } ` – Will Feb 16 '18 at 00:41
0

It is very similar in java, but all of them must be the same type:

Java: f(String... args);

It calls "Varargs" so you can google by this world for more information

Andriy Kuba
  • 8,093
  • 2
  • 29
  • 46
  • Thank you! Does this work when the function isn't declared using special syntax? – Will Feb 15 '18 at 22:08
  • I said, does this work when the function isn't **declared** using special syntax? I.e. how would you call the example given in the question statement? – Will Feb 15 '18 at 22:10
  • I am not sure what you mean under "special syntax". If you mean that you can just take arguments as variable without declaring it like in JavaScript - then no. – Andriy Kuba Feb 15 '18 at 22:11
  • about calling - yes, you do not need "special" syntax. i.e you can call it like f("A"); f("A", "B", "C") – Andriy Kuba Feb 15 '18 at 22:12
  • Got it, so given a normal method in Java, it's impossible to pass an array of arguments like in Python? – Will Feb 15 '18 at 22:12
  • I don't want to pass the array as a single argument. I want to apply the array as N arguments. – Will Feb 15 '18 at 22:14
  • If this is only possible using reflection, how would it be done? – Will Feb 15 '18 at 22:15
  • I did not mean to ask whether you can pass one argument. I asked whether you can pass an array of arguments. The elements of the array are **arguments** to the function. They are "the things you pass in". – Will Feb 15 '18 at 22:19
0

To pass unknown number of variables you would do:

public void getNumber(int...args){
      ...
}

to retrieve you would do:

args[0], args[1], args[2], ...
BlackHatSamurai
  • 23,275
  • 22
  • 95
  • 156