I was writing a method with a variable number of parameters, using the constructor proposed by Java:
public static boolean myMethod(String... strings) {
for (String s: strings) {
// Applying some logic / treatment on strings
}
}
I was wondering: how does Java behaves with the strings parameter ? Does it takes it as an ArrayList, or a simple String[] ? Is the order of the parameters kept while going through the method ?
For example, if I use my method like this:
MyMethodUtils.myMethod(first, second, third, fourth, fifth);
Am I guaranteed that first will be treated first, then second, etc ... Or not ?
Bonus question: What is the specifical name of such constructor String... (in Java) ?
Yes, ordering is preserved.
This is because String... (technically called a variable arity parameter, but often informally called "varargs") is just syntactic sugar for String[]. So:
MyMethodUtils.myMethod(first, second, third, fourth, fifth);
is identical to
MyMethodUtils.myMethod(new String[]{first, second, third, fourth, fifth});
(and in fact, you can invoke the latter).
You wouldn't expect an array's elements to change order in any other case, and nor do they with a variable arity parameter.
You can find this in JLS Sec 15.12.4.2:
If m is being invoked with k ≠ n actual argument expressions, or, if m is being invoked with k = n actual argument expressions and the type of the k'th argument expression is not assignment compatible with T[], then the argument list (e1, ..., en-1, en, ..., ek) is evaluated as if it were written as (e1, ..., en-1, new |T[]| { en, ..., ek }), where |T[]| denotes the erasure (§4.6) of T[].
Bonus question: What is the specifical name of such constructor
String... (in Java)?
Name of these type of constructors is parameterised constructor only.
The only difference is these are using Varargs.
Variable Argument (Varargs):
The varrags allows the method to accept zero or multiple arguments.
Before varargs either we use an overloaded method or take an array as the
method parameter but it was not considered good because it leads to
the maintenance problem. If we don't know how many arguments we will
have to pass in the method, var args is the better approach.
For More information
You will get these parameters in a order in which you have written , by referring your above example i can say ,
First will be first , and second will be second
As Java takes it as a string[]
Answer of bonus question
There is no specific name but the parameters you pass in such way is called as "var args"
hope you satisfied :)
Related
Of the following lines, why is the first and last allowed ?
List<String> l = new ArrayList<>();
l.stream().forEach(System.out::println);//compiles
l.stream().forEach(System.out.println(String::compareTo));//doesnt compile
l.stream().forEach(String::compareTo);// doesnt compile
String comparedWith = "";
l.stream().forEach(comparedWith::compareTo);//compiles why ?
edit
If compareTo takes one argument, shouldn't it work also ?
If according to docs:
Represents an operation that accepts a single input argument and
returns no result. Unlike most other functional interfaces, {#code
Consumer} is expected to operate via side-effects.
l.stream().forEach(System.out::println);//compiles
This calls the println method of System.out for each item. Here System.out::println is the same as (String x) -> System.out.println(x).
l.stream().forEach(System.out.println(String::compareTo));//doesnt compile
You know how function calls work, right? This first calls (System.out.println(String::compareTo), then calls l.stream().forEach(result of that println call). Except println returns void so it has no result.
l.stream().forEach(String::compareTo);// doesnt compile
Here String::compareTo is the same as (String x, String y) -> x.compareTo(y) which takes two arguments. But forEach needs a lambda that takes one argument.
String comparedWith = "";
l.stream().forEach(comparedWith::compareTo);//compiles why ?
Here comparedWith::compareTo is the same as (String x) -> comparedWith.compareTo(x). This takes one argument so it's valid.
forEach will take each element of the collection and pass it to your function. So, your function has to take only one argument.
In your case, println takes one argument, thus it fits into the operation forEach accepts. When you take the instance of the String (comparedWith) and call compareTo, it takes one argument and compares the current string (empty string in your case) with your argument. There is no static methods in String that are called compareTo, so String::compareTo doesn't work.
The double colon or more accurately called "method reference" is meant to a select a method that will be called.
And when calling methods, it matters greatly to match up the numbers of provided and expected arguments.
And as you can easily deduct, those counts do no match up for your second example.
This question already has answers here:
What is the ellipsis (...) for in this method signature?
(5 answers)
Closed 7 years ago.
I'm learning Java, and in function prototypes I often see parameters of the variety type... parameter_name. What does the ... notation mean?
The New Features and Enhancements
J2SE 5.0 says (in part)
Varargs
This facility eliminates the need for manually boxing up argument lists into an array when invoking methods that accept variable-length argument lists. Refer to JSR 201.
It's also called a variadic function. Per the wikipedia,
In computer programming, a variadic function is a function of indefinite arity, i.e., one which accepts a variable number of arguments.
Those are called varargs. When calling the method you can pass in any number of arguments for that parameter (even 0, so you can ignore it), or you can pass in an array. Inside the method the varags parameter is treated as an array.
For example, this method:
public void foo(String... strs) {}
Can be called with any of these:
foo();
foo("hello", "world");
String[] args = {"hello", "world"};
foo(args);
Inside the method you can access parameters like so:
String str1 = strs[0];
String str2 = strs[1];
One important thing to note is that a varargs parameter must be the last parameter in your method (It makes sense when you consider that the number of arguments passed can vary, so you have to resolve the other parameters first).
I was working with varargs and came to know that :-
public void myMethod(String... args, int val){}
The variable argument type String of the method myMethod must be the
last parameter.
If both will be like String, error its giving is considerable, But in this case, I am setting int as 2nd parameter, so at runtime JVM can check the type of arguments & can differentiate like :-
myMethod("HI", "HELLO", 9)
Wouldn't that be feasible. Any other point I am missing for this to be producing error?
There is a number of reasons why the language designers have chosen to disallow this:
Differentiation has to be done by the compiler, because varargs are entirely a compiler feature. They are simply converted to implicit array constructors.
Your example could in theory work out, but the restrictions would be very harsh: For example, it would be hard for the compiler to see where the first varargs parameter ends in a situation like this
void foo(Object... objs, String... s)
foo("a", "b", "c")
Another example is this:
void bar(int... ints, long... longs)
foo(1, 2, 3, 4)
You could argue that int and long are different data types, but unfortunately it is possible to use integers where long is expected due to widening conversions. And another example involves boxing:
void baz(Object... objs, int... ints)
baz(1, 2, 3, 4)
int and Object are not directly related, but int can be converted to Integer, which is a subclass of Object.
It gets even more complicated the more overloaded methods and varargs parameters you have.
A bit technical, but still relevant: in the bytecode, varargs is not a parameter attribute, but a method modifier flag (ACC_VARARGS). This means that either a method is variadic (the last parameter is varargs) or it's not.
If you really need a varargs parameter in your method, move it to the last position. The only situation in which you couldn't do this is when you have multiple varargs parameters, which is impossible for a good reason.
If the compiler would allow you do this at declaration-side without an error, it should be almost impossible to get a useful error at use-site.
String... is the same as String[], except that you don't need to create an array at use-site. You can declare a method
void foo(String[] strings, int i)
and call it as
void foo({ "a", "b" }, 2)
with just 2 more keystrokes, and without all the struggle introduced by varargs parameters.
I have been working on a JVM-language compiler for more than a year now, and I considered adding this feature as well. However, the method resolution system is already extremely complicated (and my decision to include custom infix and prefix operators / methods and named and default parameters doesn't make it any easier), and multiple varargs parameters wouldn't make it any easier.
The error message is correct. If you use varargs, it has to be the last argument. You could say it could work it out, but it won't. Just swap the order of your arguments.
This is specified in the JLS, section 8.4.1. The language specification calls for this as part of a formal parameter list:
FormalParameterList:
ReceiverParameter
FormalParameters , LastFormalParameter
LastFormalParameter
The LastFormalParameter token is where varargs are defined and permissible.
LastFormalParameter:
{VariableModifier} UnannType {Annotation} ... VariableDeclaratorId
FormalParameter
Pay attention to the .... That's the only place in the grammar of formal parameters in which this is allowed. FormalParameters does not make that allowance.
FormalParameters:
FormalParameter {, FormalParameter}
ReceiverParameter {, FormalParameter}
Disambiguation will become a nightmare when you overload methods with varargs in random positions... (not to say multiple varargs).
I'll call a method with two arguments, but i'll use k++ like this:
polygon.addPoint((int)rs.getDouble( k++),(int)rs.getDouble( k++ ));
Actually i want to be sure that jvm executes first argument first, then the second one. If somehow the order will change, arguments would be passed wrong order.
Thanks a lot!
Yes, the arguments are guaranteed to be evaluated left-to-right. Any compiler complying to JLS rules should follow that. This is mentioned in JLS §15.7.4:
In a method or constructor invocation or class instance creation
expression, argument expressions may appear within the parentheses,
separated by commas. Each argument expression appears to be fully
evaluated before any part of any argument expression to its right.
Yes, Java guarantees that. However, this does not mean that using the code like that is a good idea: readers of your code may get thoroughly confused.
It is much cleaner to show the order explicitly:
int a = (int)rs.getDouble(k++);
int b = (int)rs.getDouble(k++);
polygon.addPoint(a, b);
Java does not support named parameters, so you are correct in understanding that parameters are read in position.
For example, a method with the signature (int, String) and a method with the signature (String, int) will never be confused with each other, Java takes the type and sequence of parameters into consideration when figuring out what method to call.
Likewise, in your method, you will always have parameters coming in in a predictable and uniform fashion.
For that reason, the first k++ will always execute first, and the second k++ always after that, and that is guaranteed behaviour.
Someone asked me what the difference between the two method parameters and why you would use the ... over specifically assigned array.
putMessage(byte ...send)
putMessage(byte[] send)
I couldn't answer them with confidence and couldn't remember what the ... is called.
The ... in your first example are called varargs. Your second example has an array argument. Varargs are a convenience for times when you want to hard code a variable number of arguments to a method but don't want to manually create an array to hold them. It's a shorthand notation. Consider this:
putMessage(0b00100101, 0b00100101, 0b00100101); // varargs
vs. this:
putMessage(new byte[] { 0b00100101, 0b00100101, 0b00100101 }); // array
The first example is less cluttered and more readable.
The parameters with ellipses are generally referred to as "varargs" if you want to google that.
Using varargs allows you to call a method with variable number of arguments without having to specify an array e.g.
public void printStr(String ...strings) {
for (String s : strings) {
System.out.println(s);
}
}
> printStr("Hello", "World")
Hello
World
So varargs allow a certain degree of convenience, but there are downsides - the varargs parameter must be the last parameter in the method signature, and thus you cannot have more than one varargs parameter to a method. If you want to pass multiple arrays to a method you have to use arrays, not varargs.
Another reason you might see arrays in some places where you might expect varargs is that varargs were only introduced in Java 5 - older code and code that needs to be backwards compatible will still be using arrays even where it might make more sense conceptually to use varargs.
The advantage of using varargs in the method signature is flexibility - there are some situations where the caller will have an array ready anyway and some where they will just have several arguments. Varargs will accept either the array or each variable as a separate argument, saving the caller the trouble of instantiating and populating an array.
The first one is with Varargs.
In short
A. First can be used to call with single byte type arg, 2 byte args.. or many args or an array.
B. second will be used with array only.
The ellipsis (three dots) indicates that you are using "varargs".
See http://download.oracle.com/javase/1,5.0/docs/guide/language/varargs.html for more details.
Inside the method, you access the elements of "send" as an array. The two methods are the same in that regard. The convenience is for the caller. In the second putMessage, the caller is compelled to create an array of bytes to pass to putMessage. In the first putMessage, the caller can simply say "putMessage(byte1, byte2)" or "putMessage(byte1, byte2, byte3)" or "putMessage(byte1)" -- variable number of arguments, or varargs.
The ellipses (...) allow you to inline N parameters of a type to a function call without having to define an array first. In the end you do simply get an array of parameters but it's basically shorthand or syntactic sugar. Also your client code might be a little cleaner and more declarative with the ellipses syntax... though it could easily go the other way and become mucky and unreadable.
Here's a great example of the ellipses syntax (variable length argument lists.) While looking at the sample consider what the client code (in the main function) would look like if an array was used instead of a variable length argument list.