How to pass array of string and a string as a vararg? - java

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

How to add inputs of ArrayList <String> to a nested arraylist in java

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#"));
...

Defining an array within an if statement in java [duplicate]

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)

How to unpack an array into different arguments on method call

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.

How to convert a List<String> object to String... Object

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);

Strange Problems with Strings in Java

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];

Categories

Resources