This article is participating in “Java Theme Month – Java Debug Notes Event”, see < Event link > for more details.

Question: How do I get the common type of java.util.List?

List<String> stringList = new ArrayList<String>();
List<Integer> integerList = new ArrayList<Integer>();
Copy the code

Is there a (simple) way to retrieve common types of lists? ,

Answer 1:

If these are actually fields of a class, you can get them with the help of reflection:

package test;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

public class Test {

    List<String> stringList = new ArrayList<String>();
    List<Integer> integerList = new ArrayList<Integer>();

    public static void main(String... args) throws Exception {
        Field stringListField = Test.class.getDeclaredField("stringList"); ParameterizedType stringListType = (ParameterizedType) stringListField.getGenericType(); Class<? > stringListClass = (Class<? >) stringListType.getActualTypeArguments()[0];
        System.out.println(stringListClass); // class java.lang.String.

        Field integerListField = Test.class.getDeclaredField("integerList"); ParameterizedType integerListType = (ParameterizedType) integerListField.getGenericType(); Class<? > integerListClass = (Class<? >) integerListType.getActualTypeArguments()[0];
        System.out.println(integerListClass); // class java.lang.Integer.}}Copy the code

You can also do this for parameter types and return types of methods.

Answer 2:

You can do the same for method parameters:

Method method = someClass.getDeclaredMethod("someMethod");
Type[] types = method.getGenericParameterTypes();
//Now assuming that the first parameter to the method is of type List<Integer>
ParameterizedType pType = (ParameterizedType) types[0]; Class<? > clazz = (Class<? >) pType.getActualTypeArguments()[0];
System.out.println(clazz); //prints out java.lang.Integer
Copy the code

Answer 3:

The generic type of a collection is only important if it actually contains objects, right? So wouldn’t it be easier to do that?

Collection<? > myCollection = getUnknownCollectionFromSomewhere(); Class genericClass =null;
Iterator it = myCollection.iterator();
if (it.hasNext()){
    genericClass = it.next().getClass();
}
if(genericClass ! =null) { //do whatever we needed to know the type for
Copy the code

There are no generic types at runtime, but it is easy enough to test your project’s classes before working on them by ensuring that the objects inside the runtime are the same as the declared generic types.

Another thing you can do is simply process the list to get the right type of members and ignore the others (or process them differently).

Map<Class<? >, List<Object>> classObjectMap = myCollection.stream() .filter(Objects::nonNull) .collect(Collectors.groupingBy(Object::getClass));// Process the list of the correct class, and/or handle objects of incorrect
// class (throw exceptions, etc). You may need to group subclasses by
// filtering the keys. For instance:

List<Number> numbers = classObjectMap.entrySet().stream()
        .filter(e->Number.class.isAssignableFrom(e.getKey()))
        .flatMap(e->e.getValue().stream())
        .map(Number.class::cast)
        .collect(Collectors.toList());
Copy the code

This will give you a list of all the items whose class is a subclass of Number that you can work with as needed. The remaining items are filtered into other lists. Because they are in map, you can either process them as needed or ignore them.