How come the first call to someMethod doesn't compile without being explicit that it's String[]?
It's fine to use an array initializer to create a String[] array but you can't use it to pass an argument. Are the curly braces used in some other fashion for passing arguments that derails how I'd expect this to behave?
public void someMethod(String[] arr){
//do some magic
}
public void makeSomeMagic(){
String[] arr = {"cat", "fish", "cow"};
//Does not compile!
someMethod({"cat", "fish", "cow"});
//This compiles!
someMethod(new String[]{"cat", "fish", "cow"});
//This compiles!
someMethod(arr);
}
The compiler error is the following:
The method someMethod(String[]) in the type Moo is not applicable for the arguments (String, String, String)
You can only use the { "hello", "world" } initialization notation when declaring an array variable or in an array creation expression such as new String[] { ... }.
See Section 10.6 Array Initializers in the Java Language Specification:
An array initializer may be specified in a declaration, or as part of an array creation expression (§15.10), creating an array and providing some initial values
If you don't want to use explicit String[], use:
public void someMethod(String... arr){
//do some magic
}
…
someMethod("cm", "applicant", "lead");
The three periods after the final parameter's type indicate that the final argument may be passed as an array or as a sequence of arguments.
Read more.
Or you can use varargs:
public void someMethod(String... arr){
//do some magic
}
public void makeSomeMagic(){
someMethod("cat", "fish", "cow");
}
It's basically a fancy syntax for an array parameter (vararg must be the last parameter in method signature).
You can use the curly braces to initialize an array. In every else case it is used to define blocks of statments.
Related
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
So I was writing a Minecraft Forge mod, in eclipse, and I came around an eclipse warning that was very confusing. Though I have developed for a lot know, I do not know what the following text means.
The argument of type Block[][] should explicitly be cast to Object[][] for the invocation of the varargs method fooMethod(Object[]...) from type FooClass. It could alternatively be cast to Object[] for a varargs invocation
My Java Code:
fooMethod:
public static void registerBlock(Object[]...blocks){
for (Object[] b : blocks){
Block block = (Block) b[2];
Integer[] bb = {(int) b[0], (int) b[1]};
blocksID.put(bb, (Block) block); //Block ID
unlocalName.put(block.getUnlocalizedName(), bb);//Unlocal Name
localName.put(block.getLocalizedName(), bb); //Local Name
}
fooMethodWithWarning:
this.registerBlock(blocks);
If someone could very kindly dumb it down a little Itsy bit.
It's because what you're doing is ambiguous. It is unclear whether you're trying to do this:
// Calls the vararg method with multiple arguments
// (the arrays in blocks).
registerBlock((Object[][]) blocks);
or this:
// Calls the vararg method with a single argument (the blocks object)
registerBlock((Object[]) blocks);
Doing it the first way, when you iterate over the argument in the method each element will be an element from the 2d array. So each element will be a 1 dimensional array and there will be the same number of elements as their were in the 2d array.
Doing it the 2nd way, regardless of how many arrays were in the original array, when you iterate over the parameter in the method you will get one element and it will be the original 2d array.
To understand this, you (unfortunately) need to know how Java internally implements them.
The method signature, internally, becomes:
public static void registerBlock(Object[][] blocks)
(See JLS 15.12.4.2)
You can invoke a varargs method in two ways, either by passing all arguments as an array, or by passing them one-by-one as separate parameters. If you only provide one argument, the compiler needs to decide whether you are intending to pass only one argument as a variable argument list, or whether you are passing all your arguments as an array (with potentially many arguments).
The problem is exacerbated by the fact that an Object[] itself can is also an Object, so an Object[][] can be assigned to Object[] can be assigned to Object.
If you cast your array as Object[][] as the compiler suggests, it thinks that you are passing all varargs in one array (potentially many). If you cast it to Object[], it thinks you are passing a single vararg argument.
In this confusing case, I would advise not to use varargs - they are syntactic sugar anyway and in this case they provide more confusion than that they add convenience.
To to that, just declare your method as:
public static void registerBlock(Block[][] blocks)
From what you write in a comment on the answer above, this should fix your problem (since you are passing in a Block[][] argument to the method invocation)
... but ...
You may have a bigger problem - this will cause an exception at runtime because registerBlock is not expecting a two-dimensional array of Blocks (which you say you are passing in)
Instead, it expects the inner array to contain two Integers and then one Block.
That's not a good object-oriented style and it is the root cause of your problems.
You need to wrap these two integers and the Block into a class:
public class BlockRegistration {
private int x;
private int y ;
private Block block;
// [...]
public Block getBlock() { return block; }
public int getX() { return x; }
public int getY() { return y; }
}
and then your method becomes:
public static void registerBlock(BlockRegistration... blocks) {
for (BlockRegistration b : blocks) {
Block block = b.getBlock();
Integer[] bb = { b.x, b.y };
blocksID.put(bb, block); // Block ID
unlocalName.put(block.getUnlocalizedName(), bb);// Unlocal Name
localName.put(block.getLocalizedName(), bb); // Local Name
}
}
Check this line
for (Object[] b : blocks){
blocks should be 2 dimensional object array.
Consider the following scenario:
<T> void function(T...args){
...code...
}
And then I call it using a Integer[]. How does the compiler assume that T is an Integer, and not a Integer[]? (Note, I'm glad that this is the case, but I still find the ambiguity odd).
Furthermore, if I wanted T to be Integer[], is there anyway for me to do that (assuming boxing/unboxing doesn't exist)?
The Java compiler is smart enough to know that, since you gave it an Integer[], you probably meant for T to be Integer, not Integer[]. I'd assume this is part of the Java language specification that defines ... as varargs.
If you want to specify what T is, you can do that with the following syntax:
Integer[] ary = { 1, 2, 3 };
myObj.function(ary); // T is Integer
myObj.<Integer>function(ary); // T is Integer
myObj.<Integer[]>function(ary); // T is Integer[]
<Integer>function(ary); // this is invalid; instead you could do...
this.<Integer>function(ary); // this if it's an instance method
MyClass.<Integer>function(ary); // or this if it's static
Generics works on object references, so <T> will work on object references of a class. int[] is a class that references an array of int, while int is a primitive. Integer[] is a class that references to an array of Integer, where Integer is another class.
After reviewing this, the varargs param T ... args expects an array of object references, so int[] would be a single element in the array of object references, while Integer[] is an array of object references.
If you want to send an Integer[] as each element of your varargs, you can send an Integer[][]. I wrote an example:
public class SomeMain {
static <T> void foo(T...ts) {
for(T t : ts) {
System.out.println(t);
}
System.out.println();
}
public static void main(String[] args) {
int[] ints = { 1, 2, 3 };
Integer[] integers = { 1, 2, 3 };
foo(ints);
foo(integers);
//note, here each element in the varags will behave as Integer[]
foo(new Integer[][] { integers });
}
}
Output (the hash code of the array will change on every run):
[I#8dc8569
1
2
3
[Ljava.lang.Integer;#45bab50a
There are 3 phases in finding the applicable methods. On the 1st phase, javac tries to match argument types and method parameter types exactly. The parameter type of the method is T[] on this phase, the argument type is Integer[], the two matche after T is inferred to be Integer, therefore the method is chosen as the applicable method (there are no other overloading methods to consider). No further phases are carried out.
If the 1st phase does not yield an applicable method, javac will continue to other phases. For example, if T is explicitly specified as Integer[], the method will not match on the 1st phase (because T[] would not match Integer[])
On the 3rd phase, varargs are considered; javac will match T, not T[], with trailing argument types.
This is indeed, quite confusing, and appear to be ambiguous to our intuition.
Note that Generics isn't completely relevant to the question. The exact same question would apply if the function signature were void function(Object... args) -- if you pass an expression of type Integer[], it could interpreted as either using the array as args, or as one of the elements of args.
The answer is that, basically, the compiler will prefer to use the argument as args if possible. Since the expression you are passing has "array of reference type" type, it is compatible with args, and therefore, that interpretation prevails.
Furthermore, if I wanted T to be Integer[], is there anyway for me to
do that (assuming boxing/unboxing doesn't exist)?
Since it is a generic method, you can explicitly specify the the type argument when calling: this.<Integer[]>function(...).
But back to the more general question where the function signature is void function(Object... args). You could explicitly create the array of arguments yourself:
function(new Integer[][]{ myIntegerArray });
or (simpler) you can cast the expression to a type that is no longer an array of reference type:
function((Object)myIntegerArray);
In java we can define main() method as both these ways.
public static void main(String[] args) {
System.out.println("Hello World");
}
.
public static void main(String... args) {
System.out.println("Hello World");
}
Both method takes array of String arguments. Now consider following scenario.
String[] arr=new String[10]; // valid
String... arr=new String[10];// invalid
Java never allows to create an array like this wayString... arr=new String[10];. But in above method implementation java allows to do so. My question is how java achieve this two different behavior for two scenarios?
...
is a syntax for method arguments and not for variable definitions. The name of this notation is varargs, which is self explanatory i.e variable number of arguments.
Variable argument or varargs(...) in Java used to write more flexible methods which can accept as many argument as you need not for initialization.
... refers to varargs and its main intention to make method more readable.
void method(String... args) {
}
can be called as
method("a"); OR method("a", "b"); OR method("a", "b", "c");
I see no point in using it in variable declaration, we can't do much with
String... a = {"a", "b"}
An array can anyways be declared with dynamic size
String[] arr = {"a"};
OR
String[] arr = {"a", "b"};
You can use varargs in main because a method declared with varargs (...) is bytecode compatible with a declaration of a method with an array argument (for backwards compatibility). That does not mean that the same syntax is allowed for type declarations.
class Test{
public static void main(String... s){
System.out.println("Hello");
}
}
class Test{
public static void main(String[] s){
System.out.println("Hello");
}
}
What is the difference between above two syntax of main() declaration?
Does Java has any special need to have variable length argument?
No difference (when you run the program from the command line, i.e. what the main method is used for). The first variant appeared after Java 5 introduced varargs.
In short, varargs allows you to pass a variable number of arguments to a method. For the method body the arguments are grouped into an array. Like Test.main("foo", "bar") instead of Test.main(new String[] {"foo", "bar"}). The compiler does the array creation for you behind the scene.
The only difference is if you call main directly from other Java code. The first form allows you to write:
Test.main("first", "second", "third");
whereas the second would require you to create an array explicitly:
Test.main(new String[] { "first", "second", "third" });
Personally I don't think I've ever seen the first form used - calling main from other code is pretty rare. There's nothing wrong with it though.
There is no difference.
In general, String... s allows to pass arguments with comma as separator, while the String[] s requires an array.
But in the implementation s is array in both cases. So ... is sintactic sugar in a sense.
Variable number of arguments main(String... s) was only introduced in Java 5.0.