Java: can wildcard array types be used as parameters and return types?
•
Java
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
二维码