Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java spread operator

Tags:

java

I am not sure of the vocabulary I am using here, please correct me if I'm wrong.

In Javascript, I had the following code:

let args = [1,2,3];

function doSomething (a, b, c) {
    return a + b + c;
}

doSomething(...args);

As you can see, when calling doSomething, I am able to use the ... spread operator in order to "transform" my arguments into 1, 2, 3.

Now, I'm trying to do the same thing with Java.

Let's say I have a Foo class:

public class Foo {
    public int doSomething (int a, int b, int c) {
        return a + b + c;
    }
}

And now I want to call the doSomething:

int[] args = {1, 2, 3};

I'd like to use something like doSomething (...args) instead of calling doSomething(args[0], args[1], args[2]).

I saw that this is possible in the declaration of functions, but I'd like not to change the implementation of such a function.

like image 690
Hammerbot Avatar asked Sep 24 '17 09:09

Hammerbot


People also ask

Is there any spread operator in Java?

Sorry. There is a good reason why this is not possible in Java. You can have another method that takes say 4 integer arguments. You would not know at compile time which one to call since it depends on the length of the list which is only known at run time.

What is an spread operator?

The JavaScript spread operator ( ... ) allows us to quickly copy all or part of an existing array or object into another array or object.

What is a spread operator explain with an example?

The spread operator is a new addition to the set of operators in JavaScript ES6. It takes in an iterable (e.g an array) and expands it into individual elements. The spread operator is commonly used to make shallow copies of JS objects. Using this operator makes the code concise and enhances its readability.

Is spread and rest operator the same?

The main difference between rest and spread is that the rest operator puts the rest of some specific user-supplied values into a JavaScript array. But the spread syntax expands iterables into individual elements.


4 Answers

In java there is concept of Variable Arguments, using which you can pass different numbers of arguments to same function.

I am taking your code as an example :

public class Foo {
    public int doSomething (int ...a) {
      int sum = 0;
      for (int i : a)
           sum += i;
        return sum;
    }
 }

Now you can call this function as :

doSomething (args)

For more information you can visit below link : http://www.geeksforgeeks.org/variable-arguments-varargs-in-java/

like image 125
Nishesh Pratap Singh Avatar answered Oct 22 '22 16:10

Nishesh Pratap Singh


Actually, because for compatibility reasons, the signature of a method, which is using varargs function(Object... args) is the equivalent of a method declared with an array function(Object[] args).

Therefore in order to pass and spread any collection to function which expects varargs, you need to transform it to the array:

import java.util.Arrays;
import java.util.stream.Stream;

public class MyClass {
  
  static void printMany(String ...elements) {
     Arrays.stream(elements).forEach(System.out::println);
  }
  
  public static void main(String[] args) {
    printMany("one", "two", "three");
    printMany(new String[]{"one", "two", "three"});
    printMany(Stream.of("one", "two", "three").toArray(String[]::new));
    printMany(Arrays.asList("foo", "bar", "baz").toArray(new String[3]));
  }
}

All these calls of printMany will print:

one

two

three

It's not exactly the same as spread operator, but in most cases, it's good enough.

like image 22
Krzysztof Atłasik Avatar answered Oct 22 '22 14:10

Krzysztof Atłasik


Java language does not provide an operator to do this, but its class library has a facility to do what you need.

[from OP's comment] The developer of Foo could choose himself the number of arguments that function doSomething takes. I would then be able to construct a "bag" of arguments and inject it in the method.

Use reflection API, this is what it is for. It requires you to package arguments in an array. There is a lot of extra work required, including wrapping/unwrapping individual method arguments, and method result, but you can check the signature at run-time, construct an array, and call the method.

class Test {
    public static int doSomething(int a, int b, int c) {
        return a + b + c;
    }
    // This variable holds method reference to doSomething
    private static Method doSomethingMethod;
    // We initialize this variable in a static initialization block
    static {
        try {
            doSomethingMethod = Test.class.getMethod("doSomething", Integer.TYPE, Integer.TYPE, Integer.TYPE);
        } catch (Exception e) {
        }
    }
    public static void main (String[] ignore) throws java.lang.Exception {
        // Note that args is Object[], not int[]
        Object[] args = new Object[] {1, 2, 3};
        // Result is also Object, not int
        Object res = doSomethingMethod.invoke(null, args);
        System.out.println(res);
    }
}

The above code prints 6 (demo).

like image 17
Sergey Kalinichenko Avatar answered Oct 22 '22 14:10

Sergey Kalinichenko


Unfortunately, you can't do this. The spread operator works in javascript because functions are allowed to accept two few (left out arguments are undefined) or too many arguments (extra arguments are ignored) of any type. Java, being strongly and statically typed, must always know exactly how many and what kind of arguments you are passing before you even compile the code.

You can probably find a hackaround with Java 8's functional interfaces, method references and var-args, but it would require so much boilerplate that I won't even bother posting it here.

like image 2
Leo Aso Avatar answered Oct 22 '22 14:10

Leo Aso