4

This method is used to split array into chunks reference. I want to make this method generic.

Problem is, I can not initialize array like this.

T[][] arrays = new T[chunks][];

complete method

 public <T> T[][] splitArray(T[] arrayToSplit, int chunkSize) {
        if (chunkSize <= 0) {
            return null;
        }
        int rest = arrayToSplit.length % chunkSize;
        int chunks = arrayToSplit.length / chunkSize + (rest > 0 ? 1 : 0);
        T[][] arrays = new T[chunks][];
        for (int i = 0; i < (rest > 0 ? chunks - 1 : chunks); i++) {
            arrays[i] = Arrays.copyOfRange(arrayToSplit, i * chunkSize, i * chunkSize + chunkSize);
        }
        if (rest > 0) {
            arrays[chunks - 1] = Arrays.copyOfRange(arrayToSplit, (chunks - 1) * chunkSize, (chunks - 1) * chunkSize + rest);
        }
        return arrays;
    }

What is correct way to initialize generic array?

Hash
  • 4,647
  • 5
  • 21
  • 39
Khemraj Sharma
  • 57,232
  • 27
  • 203
  • 212

3 Answers3

7

You cannot initialise arrays with a generic parameter. That is a restriction on generics.

A workaround is to create an Object[][] and cast it to T[][]:

T[][] arrays = (T[][])new Object[chunks][];
Sweeper
  • 213,210
  • 22
  • 193
  • 313
3

You can't create a generic array, but you can declare a generic array.

T[] test = null; // works
T[] test2 = new T[10]; // fails
T[] test3 = (T[]) new Object[10]; // works

At the same time, you should be careful with this

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • is there any way to declare a generic array without the java compiler logging "uses unchecked or unsafe operations." when compiling the file that does this? `test3` causes that warning – notacorn Aug 20 '20 at 03:41
  • 1
    @notacorn no, since you can not declare a generic array, you will _always_ have the cast to `T[]`, always. – Eugene Aug 20 '20 at 10:43
1

You can't make a generic array directly since type variable information is lost at runtime due to erasure.

However, in your case there is a workaround, since the output type of the method is just an array of type arrayToSplit and arrays in Java do have their type information available at runtime.

So instead of:

T[][] arrays = new T[chunks][];

you can do:

T[][] arrays = (T[][])Array.newInstance(arrayToSplit.getClass(), chunks);

Mixing arrays and generics can be confusing and error-prone though. If possible, I would use the collections API where possible and use List<T> instead of arrays.

Guava even has a method that I think does exactly what you want:

Lists.partition(List, int)

Returns consecutive sublists of a list, each of the same size (the final list may be smaller). For example, partitioning a list containing [a, b, c, d, e] with a partition size of 3 yields [[a, b, c], [d, e]] -- an outer list containing two inner lists of three and two elements, all in the original order.

prunge
  • 22,460
  • 3
  • 73
  • 80