Why does this:
public <T> List<byte[]> getData(T data) {
Location loc = (Location) data;
// ...
}
not generate any warnings, while this:
public <T> List<byte[]> getData(T data) {
List<ScanResult> scanRes = (List<ScanResult>) data;
// ...
}
generates Type safety: Unchecked cast from T to List<ScanResult>
?
How can I resolve the warning?
As a design is this kind of method declaration a smell?
public <T> List<byte[]> getData(T data)
is an interface method implemented in different classes with different data types - the first line of all implementations is such a cast
You get the warning because the cast (List<ScanResult>) data
is not safe. Due to type erasure, List<ScanResult>
will be List
during runtime, so there will be no real type check regarding the element type of the list. That is, that cast will succeed even if you get List<String>
as a parameter and later you will get a ClassCastException
when you try to access the list:
ScanResult result = data.get(0); // ClassCastException: String
One way to avoid it is making the interface generic:
public interface DataProvider<T> {
public List<byte[]> getData(T data);
}
And then define the specific type argument at implementations:
public class DataProviderFromLocation implements DataProvider<Location> {
public List<byte[]> getData(Location data) {
}
}
public class DataProviderFromScanResultList implements DataProvider<List<ScanResult>> {
public List<byte[]> getData(List<ScanResult> data) {
}
}
I don't know if it is suitable for your needs.
From Angelika Langer's Java Generics FAQs
We are prepared to cope with ClassCastException s when there is a cast expression in the source code, but we do not expect ClassCastException s when we extract an element from a list of strings. This sort of unexpected ClassCastException is considered a violation of the type-safety principle. In order to draw attention to the potentially unsafe cast the compiler issues an "unchecked" warning when it translates the dubious cast expression.
So the answer to my first question is that the cast to SomeType
will fail there and then if the classes are not compatible - while the List<ScanResult> scanRes = (List<ScanResult>) data;
which at run time is just List scanRes = (List) data;
won't fail if data
is any List implementation - but might result in a CCE in a remote and completely unrelated part of the codebase - hence it will be real difficult to debug - hence the warning.
Another way to put it (by @erickson here) :
By doing your own cast up front, you're "complying with the warranty terms" of Java generics: if a
ClassCastException
is raised, it will be associated with a cast in the source code, not an invisible cast inserted by the compiler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With