Reputation: 39700
I'm attempting to write a method that will take a Collection<?>
and remove all objects that are not of type T
, returning either the original collection or a new collection, shown in this method signature:
public static <T,C extends Collection<T>> C objectsOfType(Collection<?> in, Class<T> type, Class<C> collectionType);
For example, I have a Collection<?>
which contains Strings, and some other objects. I want a List<String>
from it:
Collection<?> allObjects = getAllObjects();
List<String> stringObjects = objectsOfType(allObjects, String.class, ArrayList.class);
It all works out in the end. objectsOfType
will return allObjects
if it is an ArrayList
containing only Strings
, and will otherwise create a new ArrayList<String>
and populate it with the String
elements of allObjects
. I would need to add another argument to allow any List
to be returned since ArrayList
is more specific than necessary for the return value, because the class must have a constructor. But that's not the problem.
The problem is a compiler warning on the invocation of objectsOfType
, and I can't figure out why:
Type safety: Unchecked invocation objectsOfType(Collection<capture#1-of ?>, Class<String>, Class<ArrayList>) of the generic method objectsOfType(Collection<?>, Class<T>, Class<C>) of type CollectionUtilities
What's causing this warning, and how can I fix it? As far as I can tell, everything is safe. The implementation of the method itself is not in question. That doesn't raise any warnings. Only its invocation is the problem.
Upvotes: 2
Views: 85
Reputation: 25623
ArrayList.class
is not assignable to Class<C>
, i.e., Class<List<String>>
in a strict/checked context, so passing this argument requires an unchecked assignment, hence the warning. The type of ArrayList.class
is simply Class<ArrayList>
, where ArrayList
is a raw type. There is no way to use the .class
operator to specify the class ArrayList<String>
.
Do you really need the Class<C>
argument in the signature? What if you replaced it with a factory callback (e.g., something like Java 8's Supplier<C>
)?
Alternatively, just return a List<T>
(and use the same List
implementation in all cases), simplifying your signature in the process:
public static <T> List<T> objectsOfType(Collection<?> in, Class<T> type);
You could also drop the wildcard and let the compiler infer the source item type:
public static <T, R> List<R> objectsOfType(Collection<T> in, Class<R> type);
Note, however, that both of the above are lax with respect to the input collection type (which you may have intended). If you want to be strict, you could limit the input item type to a superclass of the result type:
public static <T> List<T> objectsOfType(Collection<? super T> in, Class<T> type);
Upvotes: 1