liveBook · Manning

Unchecked cast

As explained in 100 Java Mistakes and How to Avoid Them

An unchecked cast is a cast whose compatibility cannot be fully verified by the compiler or at runtime because of erased generic type information.

An unchecked cast converts between parameterized generic types when the conversion cannot be verified at run time. Java erases type arguments, so the virtual machine sees `List`, not `List<String>` or `List<Object>`. The cast may therefore vanish from bytecode while the compiler emits an Unchecked Cast warning. section 5.3.2 section 5.5

A delayed ClassCastException

A `List<String>` can be viewed as `List<?>` and then unsafely cast to `List<Object>`. Adding an `Integer` succeeds because the runtime list has no retained element-type information. The list is corrupted, but failure is delayed until code reads an item as `String`; the compiler-inserted cast on `get()` then throws `ClassCastException`. section 5.3.2

List<String> list = new ArrayList<>();
List<?> objects = list;
((List<Object>) objects).add(1);     #1
printFirstItem(list);

This short sequence isolates the time bomb: the unchecked cast permits an incompatible write, while `printFirstItem` fails only on its later typed read. section 5.3.2

Do not treat `List<String>` as `List<CharSequence>` merely because `String` implements `CharSequence`: a mutable callee could add another `CharSequence`, such as a `StringBuilder`. Prefer a wildcard when the callee only needs to read values, for example `List<? extends CharSequence>`. When mutation must be prevented, pass an unmodifiable wrapper instead of forcing a cast. section 5.3.2 section 5.5

Avoid unchecked casts with these rules:

  • Keep the declared type as specific as the actual value when possible, eliminating an unnecessary cast. section 5.5
  • Use wildcard types to express safe producer-style reads rather than casting between invariant generic collections. section 5.3.2
  • Use read-only or write-only wrappers where the required operation permits them, rather than exposing a mutable collection through an unsafe type. section 5.3.2 section 5.5
  • Treat the compiler warning as a delayed-failure risk: the eventual exception can occur far from the cast and be harder to debug. section 5.3.2 section 5.5

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Explains type erasure, compiler-inserted casts, a corrupting write, and wildcard or wrapper alternatives.
Examples
Uses a `List<String>` cast through `List<?>` to `List<Object>`, then inserts an `Integer` before a typed read.
What it assumes
Assumes familiarity with Java generic collections, casts, and subtype relationships such as `String` implementing `CharSequence`.
What you can do after
Evaluate/understand where unchecked generic casts defer ClassCastException and replace many with wildcards or wrappers.
How it connects
Connects generic type erasure, raw types, ClassCastException, wildcard types, and unmodifiable wrappers.

Also explained in

Compare how 2 books explain unchecked cast →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Java Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.