What if you try something like the following generic utility function:
public static <T> T[][] asMatrix(
Collection<? extends Collection<? extends T>> source,
T[][] target) {
// Create a zero-sized array which we may need when converting a row.
@SuppressWarnings("unchecked") T[] emptyRow =
(T[])Array.newInstance(target.getClass().getComponentType().getComponentType(), 0);
List<T[]> rows = new ArrayList<T[]>(source.size());
int i = 0;
for (Collection<? extends T> row : source) {
T[] targetRow = i < target.length ? target[i] : null;
rows.add(row.toArray(targetRow != null ? targetRow : emptyRow));
i += 1;
}
return rows.toArray(target);
}
Usage:
Collection<List<Foo>> permuted = ...;
Foo[][] result = asMatrix(permuted, new Foo[][] {});
The way it works is to visit each sub collection (i.e., row), converting it into an array. We cache these arrays in a collection. We then ask that collection to convert itself into an array, which we use as the result of the function.
The benefits of this utility function are:
- It uses
Collection.toArray
for all of the array construction and copying.
- The function is generic and so can handle any kind of reference type (unfortunately native types like
int
, long
, etc., will require more work).
- You pass in the target array, which might even be preallocated to a certain size, behaving exactly the same as
Collection.toArray
does.
- The function is tolerant of collections that change their size concurrently (as long as the collections are themselves tolerant).
- The conversion is type safe and type strict.
More examples:
List<List<Integer>> list =
Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4));
Integer[][] result;
result = asMatrix(list, new Integer[][] {});
System.out.println(Arrays.deepToString(result));
result = asMatrix(list, new Integer[][] {new Integer[] {9, 9, 9, 9}, null});
System.out.println(Arrays.deepToString(result));
Result:
[[1, 2], [3, 4]]
[[1, 2, null, 9], [3, 4]]