Java: can wildcard array types be used as parameters and return types?

For example, consider a function that accepts the ArrayList of strings, splits it into string arrays, and returns the ArrayList of these new arrays:

public static ArrayList<String[]> splitListIntoArrays(ArrayList<String> list,int divisor) {
    ArrayList<String> listSplit = new ArrayList<>();
    ArrayList<String[]> listOfArrays = new ArrayList<>();
    for (int i = 0; i < list.size(); i++) {
        listSplit.add(list.get(i));
        if ((listSplit.size() + divisor) % divisor == 0 || i == (list.size() - 1)) {
        listOfArrays.add(listSplit.toArray(new String[listSplit.size()]));
        listSplit = new ArrayList<>();
        }
    }
    return listOfArrays;
    }

Now, suppose I want to do the same thing, but for long's ArrayList:

public static ArrayList<Long[]> splitListIntoArrays(ArrayList<Long> list,int divisor) {
    ArrayList<Long> listSplit = new ArrayList<>();
    ArrayList<Long[]> listOfArrays = new ArrayList<>();
    for (int i = 0; i < list.size(); i++) {
        listSplit.add(list.get(i));
        if ((listSplit.size() + divisor) % divisor == 0 || i == (list.size() - 1)) {
        listOfArrays.add(listSplit.toArray(new Long[listSplit.size()]));
        listSplit = new ArrayList<>();
        }
    }
    return listOfArrays;
    }

Is there the best way to avoid code duplication?

Solution

Defining generic methods seems to be the most natural approach:

public static <T> List<T[]> splitListIntoArrays(List<T> list,int divisor)
  {
    ArrayList<T> listSplit = new ArrayList<>();
    ArrayList<T[]> listOfArrays = new ArrayList<>();
    for (int i = 0; i < list.size(); i++)
    {
        listSplit.add(list.get(i));
        if ((listSplit.size() + divisor) % divisor == 0 || i == (list.size() - 1))
        {
          listOfArrays.add(listSplit.toArray(new T[listSplit.size()]));
          listSplit = new ArrayList<>();
        }
    }
    return listOfArrays;
  }

I replaced the ArrayList < T > and list < T > interfaces just because they are more general

The code is good, but there is a problem: you can't create a general array like this

new T[listSplit.size()]

Is invalid java code

There are many solutions to these problems, many of which rely on reflection Better, the fastest solution is to pass the class directly to the method so that you can instantiate the array using reflection:

public static <T> List<T[]> splitListIntoArrays(List<T> list,int divisor,Class<T> clazz)
  {
    ArrayList<T> listSplit = new ArrayList<>();
    ArrayList<T[]> listOfArrays = new ArrayList<>();
    for (int i = 0; i < list.size(); i++)
    {
        listSplit.add(list.get(i));
        if ((listSplit.size() + divisor) % divisor == 0 || i == (list.size() - 1))
        {
          @SuppressWarnings("unchecked")
          T[] array = (T[]) java.lang.reflect.Array.newInstance(clazz,listSplit.size());

          listOfArrays.add(listSplit.toArray(array));
          listSplit = new ArrayList<>();
        }
    }
    return listOfArrays;
  }

So it works now:

static void test()
    {
      List<String> test = Arrays.asList("foo","bar","baz","foobar","barbaz");
      List<String[]> split = splitListIntoArrays(test,2,String.class);
      split.forEach(s -> java.lang.System.out.println(Arrays.toString(s)));


      List<Long> test2 = Arrays.asList(1L,2L,3L,4L,5L);
      List<Long[]> split2 = splitListIntoArrays(test2,Long.class);
      split2.forEach(s -> java.lang.System.out.println(Arrays.toString(s)));
    }

Output:

[foo,bar]
[baz,foobar]
[barbaz]
[1,2]
[3,4]
[5]
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>