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
.Rather than passing in the type of the list you want to instantiate, why not just pass in the empty Collection<T> that you want populated? This gives the users of your api much more flexibility, as using the default constructor is not always ideal. (for example, maybe I want a Set where I provide the expected number of elements, or I want a sorted list where I provide the Comparator).
Also, as a side note, you should always program to the most generic interface possible. In this case, your input need be nothing more specific than an Iterable, and your output a Collection.
Given this, I would write the method this way --
public static <T, C extends Collection<T>> C typesafeAdd(Iterable<?> from, C to, Class<T> listClass) {
for (Object item: from) {
to.add(listClass.cast(item));
}
return to;
}
then the calling code looks like:
public static void main(String[] args) {
List<?> untypedStringList = LegacyApi.getStringList();
List<String> typesafeStringList = typesafeAdd(untypedStringList, new ArrayList<String>(), String.class);
}
2 Comments here:
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments