In Java, how do I convert List<?>
to List<T>
using a general purpose method so that I can replace patterns like the following with a single method call:
List untypedList = new ArrayList(); // or returned from a legacy method
List<Integer> typedList = new ArrayList<Integer>();
for (Object item: untypedList)
typedList.add((Integer)item);
Note that the above code does not generate any type-safety warnings and, ideally, your solution shouldn't generate any such warnings, either.
Will the following solution work provided that list Class<L>
has a public default constructor?
public class ListUtil {
public static <T, L extends List<T>> L typedList(List<?> untypedList, Class<T> itemClass, Class<L> listClass) {
L list = null;
try {
list = listClass.newInstance();
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
}
for (Object item: untypedList)
list.add(itemClass.cast(item));
return list;
}
}
(Note that listClass.newInstance()
throws InstantiationException
or IllegalAccessException
if an instance of Class<L>
does not have a public default constructor. What problems may arise if the method does not properly handle these exceptions?)
Notes:
T
is the type of each item in the resulting list.L
is the type of the list that I wish to create (which extends List<T>
).untypedList
is the "untyped" input list, effectively the same as List<Object>
.itemClass
represents the runtime class of T
.listClass
represents the runtime class of L
.I would use Guava and its Iterables.filter(Iterable,Class) method along with a factory method from the Lists
class, like so:
List<?> original = ...;
List<String> typed = Lists.newArrayList(
Iterables.filter(original, String.class));
This will actually check each object in the original list and the resulting list will contain only those elements that are instances of the given type (String
in this case) or a subtype of it. I really don't think it makes sense to have users provide a Class
for the resulting List
type and try to instantiate it via reflection.