I'd like to be able to create a function like:
class A { private String extraVar; public String myFormat(String format, Object ... args){ return String.format(format, extraVar, args); } }
The problem here is that args
is treated as Object[]
in the method myFormat
, and thus is a single argument to String.format
, while I'd like every single Object
in args
to be passed as a new argument. Since String.format
is also a method with variable arguments, this should be possible.
If this is not possible, is there a method like String.format(String format, Object[] args)
? In that case I could prepend extraVar
to args
using a new array and pass it to that method.
You can pass arrays to a method just like normal variables. When we pass an array to a method as an argument, actually the address of the array in the memory is passed (reference). Therefore, any changes to this array in the method will affect the array.
Arrays can be passed as arguments to method parameters. Because arrays are reference types, the method can change the value of the elements.
Explanation: When sending an array to a method, the method receives the array's reference. The array reference is returned when a method returns an array. Arrays are provided to methods in the same way that regular variables are.
Passing an ArrayList to method expecting vararg as parameter To do this we need to convert our ArrayList to an Array and then pass it to method expecting vararg. We can do this in single line i.e. * elements passed. // function accepting varargs.
Yes, a T...
is only a syntactic sugar for a T[]
.
The last formal parameter in a list is special; it may be a variable arity parameter, indicated by an elipsis following the type.
If the last formal parameter is a variable arity parameter of type
T
, it is considered to define a formal parameter of typeT[]
. The method is then a variable arity method. Otherwise, it is a fixed arity method. Invocations of a variable arity method may contain more actual argument expressions than formal parameters. All the actual argument expressions that do not correspond to the formal parameters preceding the variable arity parameter will be evaluated and the results stored into an array that will be passed to the method invocation.
Here's an example to illustrate:
public static String ezFormat(Object... args) { String format = new String(new char[args.length]) .replace("\0", "[ %s ]"); return String.format(format, args); } public static void main(String... args) { System.out.println(ezFormat("A", "B", "C")); // prints "[ A ][ B ][ C ]" }
And yes, the above main
method is valid, because again, String...
is just String[]
. Also, because arrays are covariant, a String[]
is an Object[]
, so you can also call ezFormat(args)
either way.
null
How varargs are resolved is quite complicated, and sometimes it does things that may surprise you.
Consider this example:
static void count(Object... objs) { System.out.println(objs.length); } count(null, null, null); // prints "3" count(null, null); // prints "2" count(null); // throws java.lang.NullPointerException!!!
Due to how varargs are resolved, the last statement invokes with objs = null
, which of course would cause NullPointerException
with objs.length
. If you want to give one null
argument to a varargs parameter, you can do either of the following:
count(new Object[] { null }); // prints "1" count((Object) null); // prints "1"
The following is a sample of some of the questions people have asked when dealing with varargs:
As you've found out, the following doesn't "work":
String[] myArgs = { "A", "B", "C" }; System.out.println(ezFormat(myArgs, "Z")); // prints "[ [Ljava.lang.String;@13c5982 ][ Z ]"
Because of the way varargs work, ezFormat
actually gets 2 arguments, the first being a String[]
, the second being a String
. If you're passing an array to varargs, and you want its elements to be recognized as individual arguments, and you also need to add an extra argument, then you have no choice but to create another array that accommodates the extra element.
Here are some useful helper methods:
static <T> T[] append(T[] arr, T lastElement) { final int N = arr.length; arr = java.util.Arrays.copyOf(arr, N+1); arr[N] = lastElement; return arr; } static <T> T[] prepend(T[] arr, T firstElement) { final int N = arr.length; arr = java.util.Arrays.copyOf(arr, N+1); System.arraycopy(arr, 0, arr, 1, N); arr[0] = firstElement; return arr; }
Now you can do the following:
String[] myArgs = { "A", "B", "C" }; System.out.println(ezFormat(append(myArgs, "Z"))); // prints "[ A ][ B ][ C ][ Z ]" System.out.println(ezFormat(prepend(myArgs, "Z"))); // prints "[ Z ][ A ][ B ][ C ]"
It doesn't "work":
int[] myNumbers = { 1, 2, 3 }; System.out.println(ezFormat(myNumbers)); // prints "[ [I@13c5982 ]"
Varargs only works with reference types. Autoboxing does not apply to array of primitives. The following works:
Integer[] myNumbers = { 1, 2, 3 }; System.out.println(ezFormat(myNumbers)); // prints "[ 1 ][ 2 ][ 3 ]"
The underlying type of a variadic method function(Object... args)
is function(Object[] args)
. Sun added varargs in this manner to preserve backwards compatibility.
So you should just be able to prepend extraVar
to args
and call String.format(format, args)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With