java generics - cast to List issues unchecked cast warning while cast to SomeType not


java generics - cast to List<SomeType> issues unchecked cast warning while cast to SomeType not



Why this :


public <T> List<byte> getData(T data) {
Location loc = (Location) data;
// ...
}



does 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> ?


Type safety: Unchecked cast from T to List<ScanResult>



How can I appease 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





Note that having the method generic doesn't buy anything - it might as well be public List<byte> getData(Object data).
– Paul Bellora
Sep 10 '13 at 3:46


public List<byte> getData(Object data)




2 Answers
2



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:


(List<ScanResult>) data


List<ScanResult>


List


List<String>


ClassCastException


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.





And why is Location loc = (Location) data; type safe ? If I call getData("some string") wont it fail in Location loc = (Location) "some string"; again with CCE ? +1 for the parametrized interface idea
– Mr_and_Mrs_D
Sep 9 '13 at 20:09


Location loc = (Location) data;


getData("some string")


Location loc = (Location) "some string";





@Mr_and_Mrs_D (Location) data is type safe since Location is not generic type, unchecked cast warning is emitted only when casting to a generic type since the type argument is lost due to type erasure (and only List "remains" in your case).
– Katona
Sep 9 '13 at 20:17


(Location) data


Location


unchecked cast


List





@Mr_and_Mrs_D Think of it this way: at runtime, T has been erased to Object. But casting an Object to Location is still a checked cast, and will fail fast if wrong. Casting to T would be unchecked, in contrast.
– Paul Bellora
Sep 10 '13 at 3:44



T


Object


Object


Location


T





@PaulBellora: thanks that clarifies it - I apparently did not grok what "Unchecked" was about - see my answer below
– Mr_and_Mrs_D
Sep 11 '13 at 18:02



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.


SomeType


List<ScanResult> scanRes = (List<ScanResult>) data;


List scanRes = (List) data;


data



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.


ClassCastException






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

api-platform.com Unable to generate an IRI for the item of type

How to set up datasource with Spring for HikariCP?

Display dokan vendor name on Woocommerce single product pages