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?
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);
}
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]);
Related
Is there any way in Java to create a method, which is expecting two different varargs?
I know, with the same object kind it isn't possible because the compiler doesn't know where to start or to end. But why it also isn't possible with two different Object types?
For example:
public void doSomething(String... s, int... i){
//...
//...
}
Is there any way to create a method like this?
Thank you!
Only one vararg, sorry. But using asList() makes it almost as convenient:
public void myMethod(List<Integer> args1, List<Integer> args2) {
...
}
-----------
import static java.util.Arrays.asList;
myMethod(asList(1,2,3), asList(4,5,6));
In Java, only one varargs argument is allowed and it must be the last parameter of the signature.
But all it does it convert it to an array anyway, so you should just make your two parameters explicit arrays:
public void doSomething(String[] s, int[] i){
A possible API design in which the calling code looks like
doSomething("a", "b").with(1,2);
through "fluent" API
public Intermediary doSomething(String... strings)
{
return new Intermediary(strings);
}
class Intermediary
{
...
public void with(int... ints)
{
reallyDoSomething(strings, ints);
}
}
void reallyDoSomething(String[] strings, int[] ints)
{
...
}
The danger is if the programmer forgot to call with(...)
doSomething("a", "b"); // nothing is done
Maybe this is a little better
with("a", "b").and(1, 2).doSomething();
Only one vararg is allowed. This is because multiple vararg arguments are ambiguous. For example, what if you passed in two varargs of the same class?
public void doSomething(String...args1, String...args2);
Where does args1 end and args2 begin? Or how about something more confusing here.
class SuperClass{}
class ChildClass extends SuperClass{}
public void doSomething(SuperClass...args1, ChildClass...args2);
ChildClass extends SuperClass, and so is can legally exist in args1, or args2. This confusion is why only one varargs is allowed.
varargs must also appear at the end of a method declaration.
Just declare the specific type instead as 2 arrays.
Although this kind of thing is occasionally useful, usually if you find that you are hitting a restriction in Java you could probably redesign something and come out much better. Here are some possible other ways to look at it...
If the two lists are related at all you probably want to create a wrapper class for the two different lists and pass in the wrapper. Wrappers around collections are almost always a good idea--they give you a place to add code that relates to the collection.
If this is a way to initialize data, parse it from a string. For instance, "abc, 123:def, 456:jhi,789" is almost embarassingly easy to split up with 2 split statements and a loop (2-3 lines of code). You can even make a little custom parser class that parses a string like that into a structure you feed into your method.
Hmm--honestly asside from initializing data I don't even know why you'd want to do this anyway, any other case and I expect you'd be passing in 2 collections and wouldn't be interested in varags at all.
You can do something like this, then you can cast and add additional logic inside that method.
public void doSomething(Object... stringOrIntValues) {
...
...
}
And use this method like so:
doSomething(stringValue1, stringValue2, intValue1, intValue2,
intValue3);
This is an old thread, but I thought this would be helpful regardless.
The solution I found isn't very neat but it works. I created a separate class to handle the heavy lifting. It only has the two variables I needed and their getters. The constructor handles the set methods on its own.
I needed to pass direction objects and a respective Data object. This also solves the possible problem of uneven data pairs, but that is probably only for my usage needs.
public class DataDirectionPair{
Data dat;
Directions dir;
public DataDirectionPair(Data dat, Directions dir) {
super();
this.dat = dat;
this.dir = dir;
}
/**
* #return the node
*/
public Node getNode() {
return node;
}
/**
* #return the direction
*/
public Directions getDir() {
return dir;
}
}
I would then just pass this class as the vararg for the method
public void method(DataDirectionPair... ndPair){
for(DataDirectionPair temp : ndPair){
this.node = temp.getNode();
this.direction = temp.getDir();
//or use it however you want
}
}
It is not possible because the Java Language Specification says so (see 8.4.1. Formal Parameters):
The last formal parameter of a method or constructor is special: it
may be a variable arity parameter, indicated by an ellipsis
following the type.
Note that the ellipsis (...) is a token unto itself (ยง3.11). It is possible to put whitespace between it and the type, but this is
discouraged as a matter of style.
If the last formal parameter is a variable arity parameter, the method
is a variable arity method. Otherwise, it is a fixed arity method.
As to why only one and only the last parameter, that would be a guess, but probably because allowing that could lead to undecidable or ambiguous problems (eg consider what happens with method(String... strings, Object... objects)), and only allowing non-intersecting types would lead to complications (eg considering refactorings where previously non-intersecting types suddenly are), lack of clarity when it does or does not work, and complexity for the compiler to decide when it is applicable or not.
I just read another question about this "pattern", but it is already removed, so I would like to propose a different approach to this problem, as I didn't see here this solution.
Instead to force the developer to wrapping the inputs parameter on List or Array, it will be useful to use a "curry" approach, or better the builder pattern.
Consider the following code:
/**
* Just a trivial implementation
*/
public class JavaWithCurry {
private List<Integer> numbers = new ArrayList<Integer>();
private List<String> strings = new ArrayList<String>();
public JavaWithCurry doSomething(int n) {
numbers.add(n);
return this;
}
public JavaWithCurry doSomething(String s) {
strings.add(s);
return this;
}
public void result() {
int sum = -1;
for (int n : numbers) {
sum += n;
}
StringBuilder out = new StringBuilder();
for (String s : strings) {
out.append(s).append(" ");
}
System.out.println(out.toString() + sum);
}
public static void main(String[] args) {
JavaWithCurry jwc = new JavaWithCurry();
jwc.doSomething(1)
.doSomething(2)
.doSomething(3)
.doSomething(4)
.doSomething(5)
.doSomething("a")
.doSomething("b")
.doSomething("c")
.result();
}
}
As you can see you in this way, you could add new elements of which type you need when you need.
All the implementation is wrapped.
If you are not going to be passing a large number of Strings most of the time for the first argument you could provide a bunch of overloads that take different numbers of Strings and wrap them in an array before calling a method that takes the array as the first argument.
public void doSomething(int... i){
doSomething(new String[0], i);
}
public void doSomething(String s, int... i){
doSomething(new String[]{ s }, i);
}
public void doSomething(String s1, String s2, int... i){
doSomething(new String[]{ s1, s2 }, i);
}
public void doSomething(String s1, String s2, String s3, int... i){
doSomething(new String[]{ s1, s2, s3 }, i);
}
public void doSomething(String[] s, int... i) {
// ...
// ...
}
follwing on Lemuel Adane (cant comment on the post, due to lack of rep :))
if you use
public void f(Object... args){}
then you may loop using How to determine an object's class (in Java)?
like for instance
{
int i = 0;
while(i< args.length && args[i] instanceof String){
System.out.println((String) args[i]);
i++ ;
}
int sum = 0;
while(i< args.length){
sum += (int) args[i];
i++ ;
}
System.out.println(sum);
}
or anything you intend to do.
You can convert your varargs to arrays
public void doSomething(String[] s, int[] i) {
...
}
then with some helper methods to convert your varargs to array like this:
public static int[] intsAsArray(int... ints) {
return ints;
}
public static <T> T[] asArray(T... ts) {
return ts;
}
Then you can use those helper methods to convert your vararged parameters.
doSomething(asArray("a", "b", "c", "d"), intsAsArray(1, 2, 3));
I just came across varargs while learning android(doInBackground(Type... params)) ,SO posts clarified the use of it
My question is why can't we just use Arrays instead of varargs
public void foo(String...strings) { }
I can replace this type of a call by packing my variable number of arguments in an array and passing it to a method such as this
public void foo(String[] alternativeWay){ }
Also does main(String[] args) in java use varargs , if not how are we able to pass runtime parameters to it
Please suggest the benefits or use of varargs and is there there anything else important to know about varargs
The only difference between
foo(String... strings)
and
foo(String[] strings)
is for the calling code. Consider this call:
foo("a", "b");
That's valid with the first declaration of foo, and the compiler will emit code to create an array containing references to "a" and "b" at execution time. It's not valid with the second declaration of foo though, because that doesn't use varargs.
In either case, it's fine for the caller to explicitly create the array:
for(new String[] { "a", "b" }); // Valid for either declaration
Also does main(String[] args) in java use varargs , if not how are we able to pass runtime parameters to it
When it's written as main(String[] args) it doesn't; if you write main(String... args) then it does. It's irrelevant to how the JVM treats it though, because the JVM initialization creates an array with the command line arguments. It would only make a difference if you were writing your own code to invoke main explicitly.
We could use arrays instead of varargs. Varargs are syntactic sugar for using arrays. But they make your code more compact and more readable. Compare
private void foo(String... ss) { ... }
private void bar() {
...
foo("One", "Two", "Three");
...
}
with
private void foo(String[] ss) { ... }
private bar() {
...
foo(new String[] { "One", "Two", "Three" });
...
}
Similarly, we don't need the diamond operator (<>, Java 7) or lambdas (Java 8) either. But they do make code more readable and therefore more maintainable.
One advantage of varargs is for methods requiring at least one parameter, such as max. With varargs you can do it like this
static int max(int first, int... remaining) {
int max = first;
for (int number : remaining)
max = Math.max(max, number);
return max;
}
This is great, because it is impossible to pass no parameters to the max method, and the calling code for max is really clean: max(2, 4, 1, 8, 9). Without varargs the only way to have enforced the condition that at least one number should be passed would have been to have thrown an exception at runtime if the array had length 0 (always best avoided) or to force the caller to write max(2, new int[] {4, 1, 8, 9}) which is really ugly.
Because you function call looks more like a function call, ex.:
new MyAsyncTask().execute("str1", "str2");
looks better than:
new MyAsyncTask().execute(new String[]{"str1", "str2"});
There is no magic behind AsyncTask, very often you dont really need to pass any parameters, sometimes you pass parameters to constructor instead of execute. There are also implementations of AsyncTask :
https://github.com/roboguice/roboguice/blob/master/roboguice/src/main/java/roboguice/util/SafeAsyncTask.java
that dont use varargs at all
I have a class arrayFun with the variable
int[] _array;
I have a method setArray:
public void setArray(int [] array)
{
_array = array;
}
Is my set method implementation correct ?
2).How can I use this method in other class with main ?
I've tried some ridiculous options like:
arrayFun A = new arrayFun(some_constructor_values);
A.setArray(1,2,3,4,5);
That option of course doesn't work...
Try
A.setArray(new int[]{1,2,3,4,5});
Another way to solve this declare the argument as a "varargs" argument as follows:
public void setArray(int ... array) {
_array = array;
}
and then this will work:
A.setArray(1, 2, 3, 4, 5);
You can do the same with a constructor argument.
While I have your attention, it is important that you learn the Java naming conventions, and learn to follow them strictly.
A class name should always start with an uppercase letter
A variable name should always start with a lowercase letter ... unless it is a static final constant.
Using an underscore as a prefix generally frowned on.
For more information, read the Java Style Guidelines.
So your example class should look like this:
public class ArrayFun {
private int[] array;
public void setArray(int ... array) {
this.array = array;
}
}
and should be used like this:
ArrayFun a = new ArrayFun();
a.setArray(1, 2, 3, 4, 5);
You can use this instead
public void setArray(int... array) { _array = array; }
// later
ArrayFun a = new ArrayFun(some_constructor_values);
a.setArray(1,2,3,4,5);
Unless you take a copy of the array, you will be using the same array in the caller and callee.
What you're asking to do doesn't really make sense. Also, why use a function to "set the array", why not just set the array directly:
_array = newArray
You can also set an array's values like this:
int[] array = {1,2,3,4,5};
Your method's signature is :
public void setArray(int[] array)
So it accepts only one argument that is of type array of integers.
But in your method call, you are calling it as:
A.setArray(1,2,3,4,5);
In this you are passing 5 arguments to the method. So it does not match any method with 5 arguments. Thats why it does not work.
You should pass one array of integers.
You can do it in various ways :
int myArr[] = {1,2,3,4,5};
A.setArray(myArr);
or
A.setArray(new int[]new int[]{1,2,3,4,5});
Setting array the way you did is fine. But what you are setting from A.setArray(1,2,3,4,5); will throw you error saying "Method setArray(int,int,int,int,int) is not found".
You can do something like int[] ar = { 1, 2 };
a.setArray(ar);
For example, Java's own String.format() supports a variable number of arguments.
String.format("Hello %s! ABC %d!", "World", 123);
//=> Hello World! ABC 123!
How can I make my own function that accepts a variable number of arguments?
Follow-up question:
I'm really trying to make a convenience shortcut for this:
System.out.println( String.format("...", a, b, c) );
So that I can call it as something less verbose like this:
print("...", a, b, c);
How can I achieve this?
You could write a convenience method:
public PrintStream print(String format, Object... arguments) {
return System.out.format(format, arguments);
}
But as you can see, you've simply just renamed format (or printf).
Here's how you could use it:
private void printScores(Player... players) {
for (int i = 0; i < players.length; ++i) {
Player player = players[i];
String name = player.getName();
int score = player.getScore();
// Print name and score followed by a newline
System.out.format("%s: %d%n", name, score);
}
}
// Print a single player, 3 players, and all players
printScores(player1);
System.out.println();
printScores(player2, player3, player4);
System.out.println();
printScores(playersArray);
// Output
Abe: 11
Bob: 22
Cal: 33
Dan: 44
Abe: 11
Bob: 22
Cal: 33
Dan: 44
Note there's also the similar System.out.printf method that behaves the same way, but if you peek at the implementation, printf just calls format, so you might as well use format directly.
Varargs
PrintStream#format(String format, Object... args)
PrintStream#printf(String format, Object... args)
This is known as varargs see the link here for more details
In past java releases, a method that took an arbitrary number of values required you to create an array and put the values into the array prior to invoking the method. For example, here is how one used the MessageFormat class to format a message:
Object[] arguments = {
new Integer(7),
new Date(),
"a disturbance in the Force"
};
String result = MessageFormat.format(
"At {1,time} on {1,date}, there was {2} on planet "
+ "{0,number,integer}.", arguments);
It is still true that multiple arguments must be passed in an array, but the varargs feature automates and hides the process. Furthermore, it is upward compatible with preexisting APIs. So, for example, the MessageFormat.format method now has this declaration:
public static String format(String pattern,
Object... arguments);
Take a look at the Java guide on varargs.
You can create a method as shown below. Simply call System.out.printf instead of System.out.println(String.format(....
public static void print(String format, Object... args) {
System.out.printf(format, args);
}
Alternatively, you can just use a static import if you want to type as little as possible. Then you don't have to create your own method:
import static java.lang.System.out;
out.printf("Numer of apples: %d", 10);
This is just an extension to above provided answers.
There can be only one variable argument in the method.
Variable argument (varargs) must be the last argument.
Clearly explained here and rules to follow to use Variable Argument.
The following will create a variable length set of arguments of the type of string:
print(String arg1, String... arg2)
You can then refer to arg2 as an array of Strings. This is a new feature in Java 5.
The variable arguments must be the last of the parameters specified in your function declaration. If you try to specify another parameter after the variable arguments, the compiler will complain since there is no way to determine how many of the parameters actually belong to the variable argument.
void print(final String format, final String... arguments) {
System.out.format( format, arguments );
}
You can pass all similar type values in the function while calling it.
In the function definition put a array so that all the passed values can be collected in that array.
e.g.
.
static void demo (String ... stringArray) {
your code goes here where read the array stringArray
}
public MonomialPolynomial(double... coeffs){
List<IMonom> monoms = new ArrayList<IMonom>();
for (int i = 0; i < coeffs.length; i++) {
// zero coeffs might yaffect the degree
if(coeffs[i] != 0)
monoms.add(new Monom(coeffs[i], i));
}
super.monoms = monoms;
}
Why do people write double... and not [] double when they mean to array?
Is there a special meaning for this?
double... declares it a "var args" parameter -- inside your method it's identical to double[] but for the caller, it's much easier to call with varying numbers of arguments (hence var args) without the need to explicitly create an array:
Without var args:
MonomialPolynomial(double[] coeffs) { ...}
...
// explicit array creation necessary
new MonomialPolynomial(new double[] {1, 2, 3)};
With var args:
MonomialPolynomial(double... coeffs) { ...}
...
// array gets created implicitly, so less boilerplate code
new MonomialPolynomial(1, 2, 3);
Edit: One thing to watch out for with var args, only the last argument of a method can be a var args argument. This guarantess there's no ambiguity when calling a method, e.g.
foo(int a, int b...) is unambigious, because the first argument will always be assigned to a and anything after that will be go into of b.
foo(int a..., int... b) on the other hand is ambigious, there's no way to tell if foo(1, 2, 3) means a={1} and b={2, 3} or a={1, 2} and b={3}.
double... is a varargs (variable arguments) feature. This means you can provide the constructor with an array of doubles, or you can provide the constructor with any number of doubles, and it is put into an array for you. (Example: MonomialPolynomial(1.0, 5.0, 6.0).)
It is the vararg feature, that is, all the arguments the function gets are collected into an array. In that case, an array of doubles. The feature is for hardcoded arrays and such. If MonomialPolynomial were to accept a double[], you would have to use such oneliners:
MonomialPolynomial(new double[] {1, 2, 3});
But with variable arguments you may write a bit neater code:
MonomialPolynomial(1, 2, 3);