Let's say I have a method m() that takes an array of Strings as an argument. Is there a way I can just declare this array in-line when I make the call? i.e. Instead of:
String[] strs = {"blah", "hey", "yo"};
m(strs);
Can I just replace this with one line, and avoid declaring a named variable that I'm never going to use?
m(new String[]{"blah", "hey", "yo"});
Draemon is correct. You can also declare m as taking varargs:
void m(String... strs) {
// strs is seen as a normal String[] inside the method
}
m("blah", "hey", "yo"); // no [] or {} needed; each string is a separate arg here
You can directly write the array in modern Java, without an initializer. Your example is now valid. It is generally best to name the parameter anyway.
String[] array = {"blah", "hey", "yo"};
or
int[] array = {1, 2, 3};
If you have to inline, you'll need to declare the type:
functionCall(new String[]{"blah", "hey", "yo"});
or use varargs (variable arguments)
void functionCall(String...stringArray) {
// Becomes a String[] containing any number of items or empty
}
functionCall("blah", "hey", "yo");
Hopefully Java's developers will allow implicit initialization in the future
Update: Kotlin Answer
Kotlin has made working with arrays so much easier! For most types, just use arrayOf and it will implicitly determine type. Pass nothing to leave them empty.
arrayOf("1", "2", "3") // String
arrayOf(1, 2, 3) // Int
arrayOf(1, 2, "foo") // Any
arrayOf<Int>(1, 2, 3) // Set explict type
arrayOf<String>() // Empty String array
Primitives have utility functions. Pass nothing to leave them empty.
intArrayOf(1, 2, 3)
charArrayOf()
booleanArrayOf()
longArrayOf()
shortArrayOf()
byteArrayOf()
If you already have a Collection and wish to convert it to an array inline, simply use:
collection.toTypedArray()
If you need to coerce an array type, use:
array.toIntArray()
array.toLongArray()
array.toCharArray()
...
Another way to do that, if you want the result as a List inline, you can do it like this:
Arrays.asList(new String[] { "String1", "string2" });
You can create a method somewhere
public static <T> T[] toArray(T... ts) {
return ts;
}
then use it
m(toArray("blah", "hey", "yo"));
for better look.
Other option is to use ArrayUtils.toArray in org.apache.commons.lang3
ArrayUtils.toArray("elem1","elem2")
I'd like to add that the array initialization syntax is very succinct and flexible. I use it a LOT to extract data from my code and place it somewhere more usable.
As an example, I've often created menus like this:
Menu menu=initMenus(menuHandler, new String[]{"File", "+Save", "+Load", "Edit", "+Copy", ...});
This would allow me to write come code to set up a menu system. The "+" is enough to tell it to place that item under the previous item.
I could bind it to the menuHandler class either by a method naming convention by naming my methods something like "menuFile, menuFileSave, menuFileLoad, ..." and binding them reflectively (there are other alternatives).
This syntax allows AMAZINGLY brief menu definition and an extremely reusable "initMenus" method. (Yet I don't bother reusing it because it's always fun to write and only takes a few minutes+a few lines of code).
any time you see a pattern in your code, see if you can replace it with something like this, and always remember how succinct the array initialization syntax is!.
As Draemon says, the closest that Java comes to inline arrays is new String[]{"blah", "hey", "yo"} however there is a neat trick that allows you to do something like
array("blah", "hey", "yo") with the type automatically inferred.
I have been working on a useful API for augmenting the Java language to allow for inline arrays and collection types. For more details google project Espresso4J or check it out here
Related
Varargs:
public static void foo(String... string_array) { ... }
versus
Single array param:
public static void bar(String[] string_array) { ... }
Java 1.6 seems to accept/reject the following:
String[] arr = {"abc", "def", "ghi"};
foo(arr); // accept
bar(arr); // accept
foo("abc", "def", "ghi"); // accept
bar("abc", "def", "ghi"); // reject
Assuming the above is true/correct, why not always use varargs instead of single array param? Seems to add a touch of caller flexiblity for free.
Can an expert share the internal JVM difference, if there is one?
Thanks.
Arrays have been around from the beginning of Java, while varargs are a fairly recent addition. Thus a lot of older code still happily uses arrays.
Note also that calling a generic vararg method with an explicit array parameter may silently produce different behaviour than expected:
public <T> void foo(T... params) { ... }
int[] arr = {1, 2, 3};
foo(arr); // passes an int[][] array containing a single int[] element
Thus - apart from requiring a lot of effort for no clear benefit - it is not always desirable to replace legacy array parameters with varargs.
Not to mention the cases when you can't, because there is another parameter after the array in the method parameter list:
public void foo(String[] strings, String anotherParam) { ... }
Reordering the parameters may technically solve this, however it breaks client code.
Update: Effective Java 2nd. Edition, Item 42: Use varargs judiciously explains this in more details, giving also a concrete example: Arrays.asList() was retrofitted in Java5 to have vararg parameters, which inadvertently broke a lot of existing code may cause surprises when using this (now obsolete) idiom to print an array:
System.out.println(Arrays.asList(myArray));
Update2: Double checked the source, and it says that the problem occurrs with arrays of primitive types, such as int[]. Before varargs, code like this:
int[] digits = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };
System.out.println(Arrays.asList(digits));
would emit a compilation error, because only arrays of reference types could be converted to a List. Since varargs, and retrofitting asList, the code above compiles without warnings, and the unintended result is something like "[[I#3e25a5]".
The main reason not to specify everything as varargs is that it doesn't always make sense. For example, if InputStream.read(byte[]) where defined as `read(byte...) then the following call would be valid:
myInputStream.read(0, 1, 2, 3);
This would create a 4-element byte array, pass it in and then discard it.
A vararg is simple syntactic sugar for an array.
if you call foo("abc", "def", "ghi"); then
compiler will call it as foo(new String[] {"abc", "def", "ghi"});
compiler will create one new array and pass it to foo().
One can't have both foo(String...) and foo(String[]). Since both are functionally same.
in foo you specify three params,
you would have to call bar like this:
bar(new String[]{"abc", "def", "ghi"});
so that you only call it with one parameter, that is the String[]
in this case this has alsmost nothing to do with internals, your method signature for the method bar simply states that it only has one param, whereas foo has n params which are all strings
This is, how varargs are defined. The varargs extension do not make every array accepting function a varargs function. You have to call bar like this:
bar(new String[]{"abc", "def", "ghi"})
Another difference is efficiency. Objects that are inside an explicit array won't get invoked. However the parameters of a variable argument list are evaluated when the method is pushed on the stack.
This is apparent when a function call is passed as a parameter that returns the type that is used in the variable argument list.
Example:
someMethod( Object... x)
anotherMethod( Object [] );
someMethod( a(), b(), c()); // a, b and c will be invoked before you get into the method.
anotherMethod ( new Object[]{a(), b(), c()}); // The methods aren't invoked until the objects are accessed.
I was reading a book about java and the author did some variable arguments. It is something just like this:
public int num(int ... nums){}
and I did some research it looks like nums is simply an array. So I am thinking the above code can be then replaced as:
public int num(int[] nums){}
My question: What is the point of the variable arguments? Can you change the type to other types such as String?
The difference would be in how you can call the method.
If your method looked like this:
public int num(int[] nums){}
you could call it like this:
num(new int[] { 1, 2, 3 });
On the other hand, if you used varargs like this:
public int num(int ... nums){}
you could call it more concisely, like this:
num(1, 2, 3)
Varargs are just syntactic sugar that lets you write
num(1,2,3);
instead of
num(new int[] {1,2,3});
System.out.println("%s %s %s.", "this", "is", "why");
System.out.println("%s %s %s %s?", new String[] {"or", "you", "prefer", "this"});
Varargs (variable arguments) do indeed get packaged into an array when your program is run. There is no functional difference between making a call like this
public int add(int... addends);
and this
public int add(int[] addends);
Java will create an int[] for you and store it in the variable addends in the former. In the latter, you make it so the caller of the add function has to create the array themselves. This can be a bit ugly, so Java made it easy. You call the varargs method like so:
int sum = add(1,2,3,4,5,6);
And you call the array method like so:
int sum = add( new int[] {1,2,3,4,5,6} );
Varargs can be used for more than just primitives, as you suspected; you can use them for Objects (of any flavor) as well:
public Roster addStudents(Student... students) {}
A quote from the article linked:
So when should you use varargs? As a client, you should take advantage of them whenever the API offers them. Important uses in core APIs include reflection, message formatting, and the new printf facility. As an API designer, you should use them sparingly, only when the benefit is truly compelling. Generally speaking, you should not overload a varargs method, or it will be difficult for programmers to figure out which overloading gets called.
Edit: Added example for using Objects
Why is it that, if you have, let's say, these functions:
void func1(Object o){
//some code
}
void func1(Object[] o){
//some code
}
You can call, for example:
func1("ABC");
but not :
func1({"ABC", "DEF"}); // instead having to write:
func1(new Object[]{"ABC", "DEF"});
Question: Is there any special reason why the constructor needs to be called on arrays ?
The "array initialiser" is only available for declarations / assignments:
Object[] o = { 1, 2 };
Or for "array creation expressions":
new Object[] { 1, 2 };
Not for method calls:
// Doesn't work:
func1({1, 2});
It's the way it is... You can read about it in the JLS, chapter 10.6. Array Initializers. An extract:
An array initializer may be specified in a declaration (§8.3, §9.3, §14.4), or as part of an array creation expression (§15.10), to create an array and provide some initial values.
Apart from it not being defined in the JLS right now, there seems to be no reason why a future Java version wouldn't allow array initialisers / array literals to be used in other contexts. The array type could be inferred from the context in which an array literal is used, or from the contained variable initialisers
Of course, you could declare func1 to have a varargs argument. But then you should be careful about overloading it, as this can cause some confusion at the call-site
There was a suggestion that Java SE 5.0 was going to have an array literal notation. Unfortunately, we got varargs instead, with all the fun that goes with that.
So to answer the question of why, the language is just like that. You may see list literals in a later version of Java.
You are trying to perform inline array initialization which Java doesn't really support yet.
I suppose you could achieve the desired result using varargs if you so wished, but if you need to pass in an array to a method, you have to initialise it the way Java likes an array to be initialised.
When you call func1("ABC") an object of type String with value"ABC" is created automatically by java.For creating any other object other than of type String you need to used the new operator.
I'm implementing an API an have a method which you pass a list of paths where the program reads resources from
public void importFrom(String... paths) {
}
I'm using varargs to make calling the method as convenient as possible to the user, like so
obj.importFrom("/foo", "/foo/bar);
Is this an appropriate use of varargs? Or is passing in an array better?
In your case varargs is just fine. You don't really need to make an array of the paths that you will be importing because there's nothing you want to do with these paths other than to pass them along to your importFrom method.
The varargs functionality saves you from having to explicitly create an array solely for the purpose of passing a collection of values to a one-off method, which you do appear to have here.
BTW, you can still pass in an array if you want to
public class VarargsDemo {
public static void f(String... args) {
for (String s: args) {
System.out.println(s);
}
}
public static void main(String[] args) {
String[] english = new String[]{"one", "two", "three"};
f(english);
f("uno", "dos", "tres");
}
}
Because the behavior is the same, the difference comes down to a (probably minor) question of what you want the method signature to "say". When you declare a method to take an explicit array parameter, it's almost as if you want to stress that you want to operate on an array object, something that has been defined outside the method and has its own existence and importance outside the method, and one in which, perhaps, operations like indexing matter. When declaring the method with varargs, its as if you are saying "just give me a bunch of items".
Then again, this doesn't have to be true; the JVM doesn't know the difference, all it sees is an array at run time. Many programmers won't bother splitting hairs over the intent of the method signature. Varargs is all about making the calls convenient.
That said, the main limitation of varargs is that such a parameter must be the last one of the method. In your case this is not a problem, but in general it is something to consider.
Since varargs arguments get compiled into a single array argument you could generally prefer varargs since this might be more convinient in some cases and still allows to pass an array in other cases.
public void importFrom(String... paths)
{
}
compiles into
public void importFrom(String[] paths)
{
}
Alternatively you could also use Iterable<String> to make it easier to pass the arguments as collection.
The answer depends on the intended use of your function. If the user typically knows at coding time which arguments he wants to pass in, varargs is the way to go. If the user needs to be able to determine the number of arguments at runtime, an array argument will make life a lot easier for him (or her).
I think the other alternative is to use List<String>. Personally I would use a List if there are more than a few arguments or if arguments are automatically processed from somewhere (parsed from a file for example).
If you will be writing the arguments manually in the code, then I would prefer using the varargs as you proposed.
I don't understand that syntax. Trying to google various words plus "..." is useless.
It's called varargs. This fact should yield better Google results.
This is called Variadic function (wiki page with examples in many languges).
In computer programming, a variadic
function is a function of indefinite
arity, i.e. one which accepts a
variable number of arguments. Support
for variadic functions differs widely
among programming languages. There are
many mathematical and logical
operations that come across naturally
as variadic functions. For instance,
the summing of numbers or the
concatenation of strings or other
sequences are operations that can
logically apply to any number of
operands. Another operation that has
been implemented as a variadic
function in many languages is output
formatting. The C function printf and
the Common Lisp function format are
two such examples. Both take one
argument that specifies the formatting
of the output, and any number of
arguments that provide the values to
be formatted. Variadic functions can
expose type-safety problems in some
languages. For instance, C's printf,
if used incautiously, can give rise to
a class of security holes known as
format string attacks. The attack is
possible because the language support
for variadic functions is not
type-safe; it permits the function to
attempt to pop more arguments off the
stack than were placed there --
corrupting the stack and leading to
unexpected behavior. Variadic
functionality can be considered
complementary to the apply function,
which takes a function and a
list/sequence/array as arguments and
then calls the function once, with the
arguments being the elements of the
list.
One of may personal favorite not used features in Java. It is basically a reference array that is built from elements. One of the best ways to use it is on class constructor, or method where you need to constantly find a value like maximum of 2, 3, 4, 5 input elements.
One example is, when i built a generic binary tree node, for coding tasks, I used this in constructor. This enabled me simply add elements to the tree and distribute them.
Following creates String type binary tree, with root "Red" and 2 branches "Blue" and "Green".
new MBTN<String>("Red", "Blue", "Green").
Could you think what the alternatives would be :D You can't even simply make generic array of elements, so this would stretch like hell. It is definitely not useless.
They are the "variable arguments" or varargs (for short).
Basically it allows the passing of an unspecified number of Strings, so the method signature
public void printStuff(String...messages)
Effectively can handle the following calls
printStuff("hi");
printStuff("hi", "bye");
printStuff("Hello", "How are you?", "I'm doing fine.", "See you later");
You can effectively consider this a type of autoboxing. The printStuff argument can be seen as an array, so printStuff(String...messages) is conceptually handled like printStuff(String[] messages). Wtih the calls above effectively acting like
printStuff(new String[] {"hi"});
printStuff(new String[] {"hi", "bye"});
printStuff(new String[] {"Hello", "How are you?", "I'm doing fine.", "See you later"});
To access the messages internally, you use typical List handling primitives. Something like
...
if (messages != null) {
for (String message : messages) {
System.out.println(message);
}
}
...
That there is no need to actually create arrays is a bit of syntactic sugar added to Java with the advent of auto boxing.
As #BalusC mentioned, it's a varags parameter. This means you can pass a variable number of arguments to that method.
So for a method defined as
public void foo(String...strings) { }
The following invocations are legal:
foo();
foo("one param");
foo("one", "two", "three");
They are variable length parameters.
Here is one link with an example.
As mentioned by everyone...variable arguments (or varargs) allows you to do this....
//Method we're using for varargs
public void doSomething(String... datas) {
if (datas == null || datas.length == 0) {
System.out.println("We got nothing");
} else {
for (String data: datas) {
System.out.println(data);
}
}
}
Therefore, all these calls mentioned below are valid....
String d[] = {"1", "2", "3"};
doSomething(d); //An array of String, as long as the type is exactly as the varargs type.
//OR
doSomething("1", "2", "3", "4"); //I can add "infinitely" many arguments as the JVM can allocate me....
//OR
doSomething("1"); //Exactly 1;
Internally varargs is "essentially" a reference array of it's declared type.
It's a java method that took an arbitrary variable number of parameters
It means "Arbitrary number of arguments" meaning you can pass a unknown number of parameters into the method..
see
http://download.oracle.com/javase/tutorial/java/javaOO/arguments.html
Look for the "Arbitrary number of arguments" section
public Polygon polygonFrom(Point... corners) {
int numberOfSides = corners.length;
double squareOfSide1, lengthOfSide1;
squareOfSide1 = (corners[1].x - corners[0].x)*(corners[1].x - corners[0].x)
+ (corners[1].y - corners[0].y)*(corners[1].y - corners[0].y) ;
lengthOfSide1 = Math.sqrt(squareOfSide1);
// more method body code follows that creates
// and returns a polygon connecting the Points
}