I have the following code in java working fine for var args and single dimensional arrays.
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
MyConsumer<Integer> method1 = n -> n * n;
Integer[] result1 = method1.run(10);
for(Integer i : result1) {
System.out.println(i);
}
MyConsumer<Integer> method3 = n -> n * n;
Integer[] result3 = new Integer[]{10, 100};
method3.run(result3);
for(Integer i : result3) {
System.out.println(i);
}
}
}
interface MyConsumer<T> {
T execute(T args);
default T[] run(T ...args) throws ClassNotFoundException {
if (args.length > 0) {
iterate(args);
return args;
}
return null;
}
default void iterate(T ...obj) {
for (int i = 0; i < obj.length; i ) {
if (obj[i].getClass().isArray()) {
iterate(obj[i]);
} else {
obj[i] = execute(obj[i]);
}
}
}
}
Now I want this to work for multidimensional arrays as well, like for the following:
MyConsumer<Integer> method5 = n -> n * n;
Integer[][] result5 = new Integer[][]{{10, 100}, {20}};
method5.run(result5);
for(Integer[] i : result5) {
for (Integer j : i) {
System.out.println(j);
}
}
The above fails to compile with the following error
error: method run in interface MyConsumer cannot be applied to given types;
The code in the interface will work for var args and all dimensional arrays, but the problem here is to accept a multi dimensional array as varargs parameter we have to define the parameter type and return type with that no.of dimensions like for -
- 2 dimensional parameter type is
T[]... args
and return type isT[][]
- 3 dimensional parameter type is
T[][]... args
and return type isT[][][]
Can someone please suggest me the solution or other alternatives!! Solutions I thought are method overloading.
Thanks in advance!
CodePudding user response:
The most specific common supertype of T[]
, T[][]
, T[][][]
, etc. is Object[]
. So your method can take an Object[]
(or equivalently, Object...
) parameter, but that means you lose type safety -- the compiler will not check that the passed argument is type T[]
, T[][]
, T[][][]
, etc.
(Thankfully, we don't need to deal with arrays of primitive types. If we had to deal with arrays of primitive types, the only common supertype we can use is Object
, and we would have to use the methods of java.lang.reflect.Array
to interact with it generically. However, since we are only dealing with arrays of reference types, we can use the supertype of Object[]
, and can use regular array operations on the Object[]
.)
So your iterate()
method can be something like this:
default void iterate(Object... obj) {
for (int i = 0; i < obj.length; i ) {
if (obj[i] instanceof Object[]) {
iterate((Object[]) obj[i]);
} else {
obj[i] = execute((T) obj[i]);
}
}
}
Another thing to mention is that this will only work when T
isn't itself a subtype of Object[]
. This method doesn't know what T
is, and will simply recurse down to the first level that isn't an instance of Object[]
, and assumes that that is T
. But if T
is itself an array-of-reference-type type, then this will recurse down too deeply into the component type of T
.
CodePudding user response:
The answer posted by @newacct
, is correct. And it comes at a cost of manual type casting for following cases:
MyConsumer<Integer> m = n -> n * n;
Object[] res = m.run(10);
for(Object i : res) {
System.out.println((Integer)i));
}
or
MyConsumer<Integer> m = n -> n * n;
Integer[][] a = new Integer[][]{{10, 100}, {20}};
Integer[][] b = new Integer[][]{{10}, {20}};
Object[] c = m.run(a, b);
for(Object res : c) {
for (Object[] i : (Object[][])res) {
for (Object j : i) {
System.out.println((Integer)j);
}
}
}