When to prefer a varargs list to an array? - java

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.

Related

How to dynamically pass arguments as varargs in 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).

Side effects in Java methods

This might be a trivial question, but I need some clarification...
There is a book called Clean Code that says that our methods should be small, preferably up to 5-10 lines long. In order to achieve that we need to split our methods into smaller ones.
For instance, we may have someMethod() shown below. Let's say, modification of 'Example' takes 5 lines and I decide to move it into a separate method, modify 'Example' there and return it back to someMethod(). By doing this, someMethod() becomes smaller and easier to read. That's good, but there is a thing called "side effects" which says that we shouldn't pass an object to another method and modify it there. At least, I was told that it's a bad idea ) But I haven't seen anything prohibiting me from doing so in Clean Code.
public Example someMethod() {
// ... different lines here
Example example = new Example();
example = doSomethingHere(example, param1, param2, ...);
// ... different lines here
return example;
}
private Example doSomethingHere(Example example, 'some additional params here') {
// ... modify example's fields here ...
return example;
}
So, am I allowed to split the methods this way or such a side effect is prohibited and instead I should deal with a rather long-line method that definitely breaks Clean Code's rules talking about short methods?
UPDATED (more specific name for the sub-method)
public Example someMethod() {
// ... different lines here
Example example = new Example();
example = setExampleFields(example, param1, param2, ...);
// ... different lines here
return example;
}
private Example setExampleFields(Example example, 'some additional params here') {
// ... modify example's fields here ...
return example;
}
As JB Nizet commented, it's not actually a side effect if it's the only effect, so any blanket statement that "all side effects are bad" doesn't apply here.
Still, the main question stands: Is this (side) effect okay?
Talking about the principles first, side effects are, in general, dangerous for two reasons:
they make concurrency more difficult
they obscure/hide information
In your example, there is some information that is hidden. You could call this a potential side effect, and it can be exposed with a question: "Does this doSomethingHere method create a new object or modify the one I pass in?"
The answer is important, and even more so if it's a public method.
The answer should be trivial to find by reading the doSomethingHere method, especially if you're keeping your methods 'clean', but the information is nonetheless hidden/obscured.
In this specific case, I would make doSomethingHere return void. That way there's no potential for people to think that you've created a new object.
This is just a personal approach - I'm sure that plenty of developers say you should return the object you modify.
Alternatively, you can pick a 'good' method name. "modifyExampleInPlace" or "changeSomeFieldsInPlace" are pretty safe names for your specific example, imo.
we shouldn't pass an object to another method and modify it there.
Who says that? That is actually a good practice in order to split your function in a way that forms a "recipe" and have specific functions that know exactly how to populate your object properly.
What is not recommended (and probably the source where you got your recommendation misunderstood this rule) is defining a public API and modify the arguments. Users appreciate not having their arguments modified as it leads to less surprises. An example of that is passing arrays as arguments to methods.
When you define an object and pass it to an other method, method itself can modify the content of the object therein which may be unwanted in some cases. This is because you pass the reference(shallow copy) of the object to that method and method can modify that object.For example when you pass an Array, Arrays are objects, to a method, method can change the content of the Array which may not be what the caller method expects.
public static void main(String[] args){
int[] arr= {1,2,3,4};
y(arr);
//After the method arr is changed
}
public void y(int[] comingArray){
comingArray[0] = 10;
}
To make sure the values of Array cannot be changed, deep copy of the Array should be sent to method which is another story
However this is not the case when you use primite types(int, float etc.)
public static void main(String[] args){
int a= 1
y(a);
//After the method a is not changed
}
public void y(int comingInt){
comingInt = 5;
}
Due to the nature of the Objects, you should be carefulTo learn more about shallow copy and deep copy https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm

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 do you use varargs in Java?

I'm afraid of varargs. I don't know what to use them for.
Plus, it feels dangerous to let people pass as many arguments as they want.
What's an example of a context that would be a good place to use them?
Varargs are useful for any method that needs to deal with an indeterminate number of objects. One good example is String.format. The format string can accept any number of parameters, so you need a mechanism to pass in any number of objects.
String.format("This is an integer: %d", myInt);
String.format("This is an integer: %d and a string: %s", myInt, myString);
A good rule of thumb would be:
"Use varargs for any method (or constructor) that needs an array of T (whatever type T may be) as input".
That will make calls to these methods easier (no need to do new T[]{...}).
You could extend this rule to include methods with a List<T> argument, provided that this argument is for input only (ie, the list is not modified by the method).
Additionally, I would refrain from using f(Object... args) because its slips towards a programming way with unclear APIs.
In terms of examples, I have used it in DesignGridLayout, where I can add several JComponents in one call:
layout.row().grid(new JLabel("Label")).add(field1, field2, field3);
In the code above the add() method is defined as add(JComponent... components).
Finally, the implementation of such methods must take care of the fact that it may be called with an empty vararg! If you want to impose at least one argument, then you have to use an ugly trick such as:
void f(T arg1, T... args) {...}
I consider this trick ugly because the implementation of the method will be less straightforward than having just T... args in its arguments list.
Hopes this helps clarifying the point about varargs.
I use varargs frequently for outputting to the logs for purposes of debugging.
Pretty much every class in my app has a method debugPrint():
private void debugPrint(Object... msg) {
for (Object item : msg) System.out.print(item);
System.out.println();
}
Then, within methods of the class, I have calls like the following:
debugPrint("for assignment ", hwId, ", student ", studentId, ", question ",
serialNo, ", the grade is ", grade);
When I'm satisfied that my code is working, I comment out the code in the debugPrint() method so that the logs will not contain too much extraneous and unwanted information, but I can leave the individual calls to debugPrint() uncommented. Later, if I find a bug, I just uncomment the debugPrint() code, and all my calls to debugPrint() are reactivated.
Of course, I could just as easily eschew varargs and do the following instead:
private void debugPrint(String msg) {
System.out.println(msg);
}
debugPrint("for assignment " + hwId + ", student " + studentId + ", question "
+ serialNo + ", the grade is " + grade);
However, in this case, when I comment out the debugPrint() code, the server still has to go through the trouble of concatenating all the variables in every call to debugPrint(), even though nothing is done with the resulting string. If I use varargs, however, the server only has to put them in an array before it realizes that it doesn't need them. Lots of time is saved.
Varargs can be used when we are unsure about the number of arguments to be passed in a method. It creates an array of parameters of unspecified length in the background and such a parameter can be treated as an array in runtime.
If we have a method which is overloaded to accept different number of parameters, then instead of overloading the method different times, we can simply use varargs concept.
Also when the parameters' type is going to vary then using "Object...test" will simplify the code a lot.
For example:
public int calculate(int...list) {
int sum = 0;
for (int item : list) {
sum += item;
}
return sum;
}
Here indirectly an array of int type (list) is passed as parameter and is treated as an array in the code.
For a better understanding follow this link(it helped me a lot in understanding this concept clearly):
http://www.javadb.com/using-varargs-in-java
P.S: Even I was afraid of using varargs when I didn't knw abt it. But now I am used to it.
As it is said: "We cling to the known, afraid of the unknown", so just use it as much as you can and you too will start liking it :)
Varargs is the feature added in java version 1.5.
Why to use this?
What if, you don't know the number of arguments to pass for a method?
What if, you want to pass unlimited number of arguments to a method?
How this works?
It creates an array with the given arguments & passes the array to the method.
Example :
public class Solution {
public static void main(String[] args) {
add(5,7);
add(5,7,9);
}
public static void add(int... s){
System.out.println(s.length);
int sum=0;
for(int num:s)
sum=sum+num;
System.out.println("sum is "+sum );
}
}
Output :
2
sum is 12
3
sum is 21
I have a varargs-related fear, too:
If the caller passes in an explicit array to the method (as opposed to multiple parameters), you will receive a shared reference to that array.
If you need to store this array internally, you might want to clone it first to avoid the caller being able to change it later.
Object[] args = new Object[] { 1, 2, 3} ;
varArgMethod(args); // not varArgMethod(1,2,3);
args[2] = "something else"; // this could have unexpected side-effects
While this is not really different from passing in any kind of object whose state might change later, since the array is usually (in case of a call with multiple arguments instead of an array) a fresh one created by the compiler internally that you can safely use, this is certainly unexpected behaviour.
I use varargs frequently for constructors that can take some sort of filter object. For example, a large part of our system based on Hadoop is based on a Mapper that handles serialization and deserialization of items to JSON, and applies a number of processors that each take an item of content and either modify and return it, or return null to reject.
In Java doc of Var-Args it is quite clear the usage of var args:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
about usage it says:
"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. "

Passing several parameters as a single parameter in Java

I've seen an example of it before, but I've never really found any good reference material dealing with it. I know it's possible to pass in several parameters, ints for example, by defining the method as
public void aMethod(int...a)
But I don't know any more about it than that. I've seen an example, and it returned the average of the ints passed.
Is this an out-dated way of passing parameters? Is it even acceptable to use this? What exactly is the syntax like when doing this?
(Some reference material would be great)
It's called varargs (from the C syntax). See Sun's varargs guide for an overview and this JDC Tech Tip for usage. It is not out-dated; it was put in as a feature request since previously you were forced to create an array or list, which was really ugly for supporting something like C's printf.
public void myMethod(String... args) {
for (String aString:args) {
System.out.println(aString);
}
}
You are going to have to pass a list of ints to the method to do this, something like this:
public void aMethod(int[] list)
or this:
public void aMethod(ArrayList<int> list)
It would be nice if Java had something like C#'s params keyword but it doesn't.

Categories

Resources