How do you cast a List of supertypes to a List of subtypes?
To convert a List<SuperType>
to List<SubType>
, employ a filtered copy since generics in Java prohibit direct casting:
Here, Stream, using filter and map operations, ensures type safety and thus prevents ClassCastException
at runtime.
Exceptions to avoid direct casting
There may be scenarios where direct casting might prove beneficial, these include:
- Absolute certainty that the list contains only
SubType
instances. - Performance-driven contexts where cost of individually casting each element is prohibitive.
In such cases, you can utilize @SuppressWarnings("unchecked")
to suppress warnings, acknowledging that you've done your due diligence in verifying the list's content:
Nitty-gritty of generics and type safety
Java's type system is there to enforce type safety at compile time. Due to the invariant nature of generic types in Java, a List<SuperType>
is not a List<SubType>
. Here's why casting at the list level is problematic:
- Type Erasure: At runtime, instances of
List<SuperType>
andList<SubType>
become simplyList
. The JVM doesn't keep track of the generics. - Risk of Runtime Exceptions: Without checking each element, an insertion of a
SuperType
object that isn't aSubType
will trigger aClassCastException
at runtime.
Alternative design options
Instead of casting, take a peek at some designs that eliminate the need for casting:
- Use polymorphism: define methods in
SuperType
thatSubType
can elegantly override. - Adopt the Visitor Pattern: to separate operations from the object structure.
- Paint with generics and wildcards (
List<? extends SuperType>
): to write more flexible and readable code.
Dealing with unchecked warnings
When the demon of casting cannot be exorcised due to legacy code or unyielding constraints, @SuppressWarnings("unchecked")
comes to the rescue:
- Break the glass for suppression only when you have an iron grip over the list contents.
- Always document why the suppression is safe and how you've locked type safety into the cellar.
Casting limitations and workarounds
Casting a List<SuperType>
to a List<SubType>
is like trying to fit a square peg in a round hole due to type erasure and invariance:
- Generics snarl at the sight of array creation, e.g.,
new List<SubType>[10]
, rules of the game make generic array creation illegal. - Parameterized types give the
instanceof
operator a cold shoulder, e.g.,if (list instanceof List<SubType>)
. Workarounds exist, but caveats apply.
Was this article helpful?