How to dynamically pass arguments as varargs in Java - java

I'm trying to write a program that will take an unknown number of arrays as input from the user and then print from them, the function that I wrote that print takes in varargs.
So what I'm trying to do is in my main method call print(arr1, arr2, arr3...) and dynamically change that so I don't have to set a restriction on how many arrays can be passed in.
My initial thought process was to store all the arrays in a 2d ArrayList and then unpack them, much like how JavaScript has the spread operator where you can have a 2d array and then do print(...inputArrays), but it doesn't seem like Java allows this.

This method:
public void foo(String... args) {}
is effectively the same as:
public void foo(String[] args) {}
Really - check the bytecode, it's the same signature. Or try to make both of these methods in one class - the compiler won't let you, as they have the same signature. The one difference between String... and String[] is that any callers to String... get the syntax sugar of: Take all arguments passed in this position and create an array for them.
As a consequence, invoking a varargs method and passing in an array works fine:
public void foo(String... args) {
}
String[] a = new String[10];
foo(a); // compiles and runs fine.
The problem is that arrays in java are rather unwieldy, but varargs is based on them. You're on the right track to avoid them, but when trying to dynamically call varargsed methods you're forced into using them. To make matters worse, generics and arrays don't mix well either. Nevertheless:
getPermutations(inputArrayList.toArray(ArrayList[]::new));
should get you somewhere (this converts the arraylist into an array).

Related

How did JVM implement array's class?

Can I override any methods of array?
For example toString() or other methods.
import java.lang.reflect.Method;
public class ArraysClassTest {
static int[] array = { 1, 2, 3, 1 };
public static void main(String[] args) {
Class<? extends int[]> class1 = array.getClass();
try {
Method method = class1.getMethod("toString");
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
You can't change any features of arrays. JLS §10.7 Array Members specifies every member of an array:
The members of an array type are all of the following:
The public final field length, which contains the number of components of the array. length may be positive or zero.
The public method clone, which overrides the method of the same name in class Object and throws no checked exceptions. The return type of the clone method of an array type T[] is T[].
A clone of a multidimensional array is shallow, which is to say that it creates only a single new array. Subarrays are shared.
All the members inherited from class Object; the only method of Object that is not inherited is its clone method.
The specification doesn't allow any way of customizing this implementation. An array's toString() method, for example, is always the basic one inherited from Object.
To create an array object the compiler emits one of three instructions into the compiled Java bytecode: newarray for primitives, anewarray for reference types, or multinewarray for all multidimensional arrays. In implementing those instructions, the virtual machine creates each array class as needed at runtime (JVMS §5.3.3 Creating Array Classes). The VM also defines dedicated bytecode instructions for the compiler to use for getting and setting elements of arrays and getting an array's length.
How the arrays are implemented within the VM is not specified whatsoever. It is purely an implementation detail, and even the Java compiler doesn't know, or care. The actual code involved depends on the flavor of virtual machine you're running your program on, the version of that VM, the OS and CPU it's running on, and any relevant runtime options the VM is configured with (e.g., whether in interpreted mode or not).
A quick look over the OpenJDK 8 source code turns up some of the relevant machinery for arrays:
src/share/vm/oops/arrayKlass.cpp
src/share/vm/oops/objArrayKlass.cpp
src/share/vm/oops/typeArrayKlass.cpp
src/share/vm/interpreter/bytecodeInterpreter.cpp – implements bytecode instructions for the interpreter, including instructions for creating and accessing arrays. It's tortuous and intricate, however.
src/share/vm/c1/c1_RangeCheckElimination.cpp – performs some clever array bounds check eliminations when compiling from bytecode to native code.
As arrays are a core feature of the language and the VM, it's impossible to point to any one source file and say "here, this is the class Array code". Arrays are special, and the machinery that implements them is literally all over the place.
If you want to customize the behavior of an array, the only thing you can do is not use the array directly, but use, subclass, or write, a collection class that internally contains the array. That gives you complete freedom to define the class's behavior and performance characteristics. However, it is impossible to make a custom class be an array in the Java language sense. That means you can't make it implement the [] operator or be passable to a method that expects an array.
In Java, all arrays (including those of primitive types) have java.lang.Object as their base class. (For one thing this is how zero length arrays can be modelled).
Although it's possible to override any method in that base class, Java itself specifies the form of the array. You are not able to interfere with that: in particular you can't extend an array.
To answer your direct question: no, you can't.
Arrays are a "compiler" construct - the compiler knows what String[] means; and it creates the corresponding byte code out of that. You can only create array objects, but not "new array classes". Or beyond that, the JVM knows what to do about "array using" bytecode instructions.
In other words: the source code that defines the behavior of Array-of-something objects is completely out of your control. Arrays just do what arrays do; no way for you to interfere with that.
And to get to your implicit question why things are this way:
Sometimes there isn't much to understand; but simply to accept. Thing is that the Java language was created almost 20+ years ago; and at some point, some folks made some design choices. Many of them were excellent; some of them might have been handled if we would redo things nowadays.
You will find for example, that Scala has a different way of dealing with arrays. But for java, things are as they are; and especially for things that are "so core" to the language as arrays, there is simply no sense in changing any of that nowadays.
You can create a proxy and use it in place of the original object
final int[] array = { 1, 2, 3, 1 };
Object proxy = Proxy.newProxyInstance(array.getClass().getClassLoader(), array.getClass().getInterfaces(), new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
StringBuilder b=new StringBuilder("the array is");
for(int i:array)
b.append(" ").append(i);
return b.toString();
}
});
System.out.println(proxy.toString());
the output of the above is "the array is 1 2 3 1".

How does 'variable length arguments' work in Java?

According to my understanding, a method with variable length argument and another method with array as an argument are interchangeable. for eg.
void test(int ... ints){} //method-1
is same as
void test (int [] ints){} //method-2
and we can't use both in the same class (Compile Time Error).
When I use method-1, I can call this method by passing some integers or by passing an array of integers since calling this method using some integers will implicitly create an array of those integers.
For eg.
test(1,2,3); //ok
test(new int[5]); //ok
But,
When I use method-2, I can't call this method by passing some integers as arguments.
test(new int[5]); //ok
test(1,2,3); //NOT OK
Questions:
1) If java implicitly creates an array of the arguments, why it is not able to call test(1,2,3) in case of method-2.
2) Why java doesn't allow using method-1 and method-2 together when both show different behavior?
One difference I could think of is you can have additional arguments to a metod after an int[] but you cant have a variable argument like that. Variable argument should always be the last parameter to a method. Example
void test(int[] a, int a) {} // works fine.
void test(int ... ints, int a){} // compile error.
1) If java implicitly creates an array of the arguments, why it is not
able to call test(1,2,3) in case of method-2.
Because 1,2,3 in test(1,2,3) is not an array, these are three different integers...You have to pass an Array of int to invoke method-2.
2) Why java doesn't allow using method-1 and method-2 together when
both show different behavior?
It creates ambiguity when you call method with array as an argument because array as an argument is allowed in case of varargs as well as array as an argument.
for example, if both method were allowed, test(new int[5]) will create an ambiguity.
The internal representation in the Java compiler of the function declarations in these two cases is identical. That's why the compiler wont let you declare two such functions with the same name.
The difference in the bahivour of these two declarations can be seen when you actually call the functions with the actual arguments. Since Java is a strongly typed language (with strict type checking) it doesn't allow you to pass three integers to the test (int[] a) method.
However, when you call test(int ... a) with test(1,2,3) the compiler generates intermediate code to make a temporary array of three integers and passes it onto the function.

Passing array as argument BUT individually

I want to have an abstract function such as
init(int... conditions);
So that inherited classes can have variety of init conditions; may some classes require less number of arugments and may others will take more than the others.
However I wish to rather pass them individually like following
init(arr[0], arr[1], arr[2]... arr[size-1]);
than
init(arr);
Is such approach possible? If not, then should I be better of just passing an array?
Sorry for the confusion that I seem to create.
I have an array of size n that varies.
I cannot hard code passing the argument because the number of arguments is dependable.
I do not want to go for function overload for different versions of init method because that will create about dozen of different versions of init method.
You don't need to overload the method. Just use the so called variable arguments. The are available in Java since version 1.5. For example:
public void init(int... conditions) { ... }
You can use the method in two ways:
Pass the array itself. Like this:
init(array);
Pass each of the array elements. Like this:
init(array[0], array[1], ... array[n]);
Note that if you want to have other arguments for this method, they should be placed in the method signature only before the variable arguments.
You can always use the variable arguments method parameter. In fact it has the same method signature as what you posted above.
public void init(int... conditions){}
This makes conditions an int[], which you can iterate over to get your init conditions.

When to prefer a varargs list to an array?

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.

Difference between byte[] and byte ... in Java Methods

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.

Categories

Resources