I want to pass an array and a single object to method which has varargs.
However, the most obvious solution doesn't seem to work:
public static final String[] ARRAY_ARGS = {"first argument", "second argument"};
public static String additionalArgument = "additional argument";
public static void foo(String... args) {
// ...
}
public static void main(String[] args) {
foo(ARRAY_ARGS,additionalArgument); // error! won't compile
}
How can I fix this?
A variable argument is equivalent to an array. Hence, the compiler does not accept an array and a string. One solution is to create an array from the original with the additional string added to it:
List<String> originalList = Arrays.asList(ARRAY_ARGS);
List<String> list = new ArrayList<String>(originalList);
Collections.copy(list, originalList);
list.add(additionalArgument);
foo(list.toArray(new String[list.size()]));
The Collections.copy is needed because adding to the list returned by Arrays.asList throws a java.lang.UnsupportedOperationException as the latter returns a list that extends AbstractList which does not support adding elements.
Another solution is to create a new array and individually add the elements:
String[] arr = new String[3];
arr[0] = ARRAY_ARGS[0];
arr[1] = ARRAY_ARGS[1];
arr[2] = additionalArgument;
foo(arr);
Or you can simply call foo with the individual parameters:
foo(ARRAY_ARGS[0], ARRAY_ARGS[1], additionalArgument);
You can do this, if the first argument to your method is the single string, followed by the varargs:
public static void foo(String a, String... args) {
System.out.println("a = " + a);
System.out.println("args = " + Arrays.toString(args));
}
Then calling foo("a", "b", "c") prints
a = a
args = [b, c]
The argument String ... args is shorthand for String[]. Therefore you get an error when you are calling foo(args,additionalargument) since the method declaration of foo is foo(String[] str) instead of foo(String[],String).
If you must distinguish between the array and the single string, concatenate the array values in a format you can "recognize", pass the "array-string" and the single string as parameters to the main method, and then parse the "array-string" in the relevant (foo) method.
A Java 8 approach to solve this problem is the following oneliner:
foo(Stream.concat(Arrays.stream(ARRAY_ARGS), Stream.of(additionalArgument)).toArray(String[]::new));
This creates a new String[] that can be passed to foo. Furthermore, foo must be made static, otherwise the code will not compile.
The only parameters that you can pass to the foo-method is either a String array or a bunch of individual Strings.
Simple yet elegant solution using Apache Commons Lang library:
foo(ArrayUtils.addAll(ARRAY_ARGS,additionalArgument));
Related
I have a method that takes in a nested ArrayList of Strings as a parameter as given below:
public static String methodName(ArrayList<ArrayList<String>> param1,ArrayList<Integer> param2){
...some logic
}
I want to test this method with an input
input :"param1"= [
["HTML", "C#"],
["C#", "Python"],
["Python", "HTML"]
]
"param2"= [0, 0, 1]
I searched online and found this : How do I declare a 2D String arraylist?
Here is what I tried:
public static void main(String[] args){
ArrayList<ArrayList<String>> param1 = ...what should I put here?
List<List<String>> list = new ArrayList<List<String>>();
List<String> input = new ArrayList<String>();
input.add({"HTML", "C#"});//does not compile ... array initializer not allowed here
input.add({"C#", "Python"});
input.add({"Python", "HTML"});
How would you add the input to the nested ArrayList?
Would appreciate any help...
Since param1 is declared as ArrayList<ArrayList<...>>, you have no choice, but to create new ArrayList(...) explicitly for nested elements:
ArrayList<ArrayList<String>> param1 = new ArrayList<>(Arrays.asList(
new ArrayList<>(Arrays.asList("HTML", "C#")),
new ArrayList<>(Arrays.asList("C#", "Python"))
));
But, as the general rule, try to write functions that accept as permissive parameter types as possible. In this case, if you can replace ArrayList<ArrayList<String>> in methodName with List<List<String>>, that would be much better for the users of your function.
For example, they would be able to create param1 as such:
List<List<String>> param1 = Arrays.asList(
Arrays.asList("HTML", "C#"),
Arrays.asList("C#", "Python")
);
UPD as #DavidConrad pointed out, you can use List.of(...) instead of Arrays.asList(...) since Java 9.
You could do
List<List<String>> list = new ArrayList<>(); // No need for List<String> again, just the one diamond operator is enough here.
list.add(List.of("HTML", "C#"));
...
public class Sonnet29 implements Poem {
private String[] poem;
public Sonnet29() {
poem = { "foo", "bar" , "baz"};
}
#Override
public void recite() {
//...
}
}
Line poem = { "foo", "bar" , "baz"}; is giving compilation error.
Any specific reason why this is not allowed?
How do I initialize a String array with array constants?
EDIT: Thank you folks for your answers. Now I'm clear what is allowed and what is NOT.
But can I ask you why this is NOT allowed?
String[] pets;
pets = {"cat", "dog"};
After googling a bit, I found this link, where in, it is told that coding like this leaves the compiler in ambiguity - whether the pets should be array of Strings or array of Objects. However from the declaration, it can very well figure out that it is a String array, right???
This will do what you're looking for:
public Sonnet29() {
poem = new String[] { "foo", "bar", "baz" };
}
Initialization lists are only allowed when creating a new instance of the array.
From 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
In short, this is legal code:
private int[] values1 = new int[]{1,2,3,4};
private int[] values2 = {1,2,3,4}; // short form is allowed only (!) here
private String[][] map1 = new String[][]{{"1","one"},{"2","two"}};
private String[][] map2 = {{"1","one"},{"2","two"}}; // short form
List<String> list = Arrays.asList(new String[]{"cat","dog","mouse"});
and this is illegal:
private int[] values = new int[4];
values = {1,2,3,4}; // not an array initializer -> compile error
List<String> list = Arrays.asList({"cat","dog","mouse"}); // 'short' form not allowed
{"cat", "dog"}
Is not an array, it is an array initializer.
new String[]{"cat", "dog"}
This can be seen as an array 'constructor' with two arguments. The short form is just there to reduce RSI.
They could have given real meaning to {"cat", "dog"}, so you could say things like
{"cat", "dog"}.length
But why should they make the compiler even harder to write, without adding anything useful? (ZoogieZork answer can be used easily)
I would like to know if it is possible to unpack an Object array into separate Object on method call which accepts vargs. This question is similar to this one.
I have a code like:
public class Test {
public static Object doWork(Object... objects){
System.out.println(objects.length);
return objects;
}
public static void main(String[] args){
Object res = doWork("one", "two");
res = doWork("three", res);
}
}
I would like to unpack the res object in the second call so it would receive an object array with length 3 instead of length 2 as now (where the second position is an Object array of length 2, having then all three arguments).
Is even that possible in Java?
More detailed:
By doing
Object res = doWork("one", "two");
res = doWork("three", res);
the second call gets called as:
doWork( Object[ "three", Object[ "one", "two" ] ] )
where i would like:
doWork(Object[ "one", "two", "three" ] )
I know this can be achieved by doing:
public static void main(String[] args){
res = doWork("one", "two");
List<Object> los = Arrays.asList(res);
los = new ArrayList<>(los); // Can't modify an underlying array
los.add("three");
res = doWork(los.toArray());
}
But I'm looking for something like the unpack Lua built in function or the Python way described in the previously mentioned SO question.
Both answers given by #chancea and #Cyrille-ka are good and also solve the problem. One of the facts that might be a good idea to take into account is if the signature of the method can be modified.
#cyrille-ka answer respects the function's signature, whereas #chancea does not. However I think in most cases one can just write asimple wrapper function to another one, so that shouldn't be a problem.
On the other hand #chancea's way might be easier to use while programing (there no possible mistake of forgetting to call the unpack function).
Well, there is no syntactic sugar à la Python or Lua for that in Java, but you can create your own unpack method:
#SafeVarargs
public static <E> Object[] unpack(E... objects) {
List<Object> list = new ArrayList<Object>();
for (Object object : objects) {
if (object instanceof Object[]) {
list.addAll(Arrays.asList((Object[]) object));
}
else{
list.add(object);
}
}
return list.toArray(new Object[list.size()]);
}
This will returns an array containing all the input elements, unpacked.
Then you can call it in your main method:
res = doWork(unpack("three", res));
The reason I make this method generic is that you can call it with, for example, a String[] array, without generating a warning. For some reason, the Java compiler thinks that this method has a chance of "polluting the heap", but it is not the case, that's why I added a #SafeVarargs annotation.
This does not implement the Unpack solution, instead it goes about it by making an overload method as I said in my comment. I do not know if this at all what you wanted, but I got it to work and I felt like I would post this for reference.
public class Test {
public static Object doWork(Object... objects){
System.out.println(objects.length);
return objects;
}
// this is the method that will concatenate the arrays for you
public static Object doWork(Object[] objects1, Object... objects2){
System.out.println(objects1.length + "+" + objects2.length);
Object[] retval = new Object[objects1.length+objects2.length];
System.arraycopy(objects1, 0, retval, 0, objects1.length);
System.arraycopy(objects2, 0, retval, objects1.length, objects2.length);
return retval;
}
public static void main(String[] args){
Object res = doWork("one", "two");
res = doWork((Object[])res, "three");
Object[] res2 = (Object[])res; // = {one, two, three}
}
}
Try to return as an array of Object instead. Then concatenate "three" at the end of the returned array.
Recently I came across an API and it was using some Parameter
void doSomething(final String... olah) {
}
I never have seen something like that.
I have a List<String> now and I want to call that function with my list of string. How can I achieve that?
Welcome to modern Java. That syntax is called varargs in Java.
http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
You can think of it like
void doSomething(final String[] olaf) {
}
The only difference is that as the name suggests, it is Variable Length Arguments. You can invoke it with 0 to any number or arguments. Thus, doSomething("foo"), doSomething("foo", "bar"), doSomething("foo", "bar", "baz") are all supported.
In order to invoke this method with a List argument though, you'll have to first convert the list into a String[].
Something like this will do:
List<String> myList; // Hope you're acquainted with generics?
doSomething(myList.toArray(new String[myList.size()]));
String... is nothing but String[]. So just loop over list and create an array of String and pass that array or more easy way to use .toArray(new String[collection.size()]) method of Collection class.
String... is the same as String[].
You want to call something like:
String[] listArr = list.toArray( new String[ list.size() ] );
doSomething( listArr );
Use .toArray(new String[0]). The toArray() method will turn your list of strings (java.util.List<String>) into an array of String objects.
The '...' syntax is a mechanism to allow a variable number of parameters. You can pass either something like doSomething("abc", "def", "ghi") or doSomething("abc") or doSomething(new String[] { "abc", "def", "ghi" }). The function will see them all as arrays (respectively as length 3, 1 and 3).
See the following to convert List of String to String Array
List<String> listOfString = new ArrayList<String>();
listOfString.add("sunil");
listOfString.add("sahoo");
String[] strResult=new String[listOfString.size()];
strResult = listOfString.toArray(strResult);
I am new to JAVA and found some of its concepts very irritating and no matter how hard I try I can not find suitable explanation for this behavior...of course there are wor around for these problems but still I want to know am I missing something very simple here or JAVA is like this???
I have a string array in one of my class A and I want it to be filled through a method of another class B...so I create an object of class B into A and call the method B.xyz and equate it to the string arra but BOOM I can't do it....java throws a nullpointer exception..........I dont know why...
.
public class B{
public void xyz() {
String[] mystrings=new String[70];
for(int i=0;i<5;i++)
mystrings[i]=value;
return mystrings;
}
}
public class A {
public void abc() {
B b=new B();
String[] StringList;
StringList=b.xyz();
System.out.println(StringList.length);
}
}
I have a similar code fragment now sadly the length of the StrinList becomes 70....if I want to print all the strings of this array I dont have any other way....remember even though the size of mystring is 70 in class B only 5 of its components are properly initialized........SO considering I am in class A and have no way to find out how many times did the for loop in B executed......how do I accurately loop through all the elements of StringList in A.........
PS: There are workarounds to solve this problem but I wanted to know why this happens,i.e, why the length attribute doesn't change according to the components initialized??
If you only need an array of length 5 then only initialize it as that size, e.g.:
public String[] xyz(String value) {
String[] mystrings = new String[5];
for (int i = 0; i < mystrings.length; i++) {
mystrings[i] = value;
}
return mystrings;
}
If you want an array that you can expand you should consider using ArrayList instead. E.g.:
public List<String> abc(String value) {
List<String> list = new ArrayList<String>();
for (int i = 0; i < 5; i++) {
list.add(value);
}
return list;
}
Then you can get its size, add to it and print the elements like this:
List<String> list = abc("foo");
System.out.println(list.size());
list.add("bar");
for (String value : list) {
System.out.println(value);
}
Hope that helps.
You declared xyz as a method with return type void in class B. Presumably you want a signature that returns a string array, public String[] xyz()
Also you didn't declare the array correctly in B, the correct declaration is:
String[] myStrings = new String[70];
-- Dan
String[] mystrings = new String[5];
I suggest you look at using List like ArrayList as this wraps arrays to make them easier to use.
String[] mystrings[70];
This creates an array or arrays. There are two []
I suggest you try instead.
String[] mystrings = new String[5];