Last time I talked about using generics to make getting values out of collections nicer (and a proposal that would obviate their use) so this time I want to talk about the other half–passing items into a collection. This encompasses all methods that take a parameter of the collection’s generic typing including those that add items to the collection.
If you look at the byte-codes generated for calling any of these methods you will see that there is no runtime checking of the objects being passed. This is because the methods of the base object are defined as taking
Object types. The only checking happens at compile time. So as long as the static type is correct everything is fine but it is easy to override the static type (accidentally or on purpose) so what happens? Well, if you attempt to retrieve a value from the collection and the type is not assignment compatible with the target then you will get a
Let’s think about that for a moment. The exception is not thrown when the invalid value is added to the collection (when tracking down the error would have the context of the situation) but when it is removed (or examined). This defeats the basic rule of “fail as early as possible”. It also means that a statement with no cast operator can fail with a class cast exception. This seems counter to the spirit of the language and in fact leads to confusion. You look at the line that the stack trace points to and say to yourself “there is nothing there that can throw a class cast exception.” After a this hits you a time or two you will remember but why should you have to make that effort?
I will grant that the generic definition does make it harder to accidentally put in the wrong thing, but it doesn’t eliminate it entirely. If we are going to have a
checkcast byte-code on retrieving the value then why don’t we have it on putting the value in as well?