liveBook · Manning

Raw type

As explained in 100 Java Mistakes and How to Avoid Them

A raw type is a generic Java type used without its type arguments, disabling compile-time checking for those arguments.

A raw type uses a generic class or interface without its type arguments: `List` instead of `List<String>`. It suppresses the compile-time guarantees supplied by the generic declaration, so values can enter a collection without being checked against the intended element type. section 5.3.2 section 8.2

Generics are checked in source code, but type arguments are erased at run time. The virtual machine sees `List`, and a call such as `list.get(0)` yields `Object`; when source code expects `String`, the compiler supplies an implicit cast. A wrongly populated list can therefore remain apparently valid until a later read triggers `ClassCastException`. section 5.3.2

A delayed failure from a raw List

`List list = new ArrayList<>(); list.add(123); printFirstItem(list);` can compile with a raw-type warning. Inside `printFirstItem(List<String>)`, retrieving the first value requires a cast to `String`; the inserted `Integer` makes that cast fail. The raw declaration is the entry point that bypasses the intended `List<String>` constraint. section 5.3.2

List list = new ArrayList<>();     #1
list.add(123);
printFirstItem(list);

Compare the raw declaration and unchecked insertion with the method that expects `List<String>` to see where type safety is lost and where failure appears. section 5.3.2

Unchecked casts can create the same corruption even when a variable is not declared raw. Casting `List<?>` to `List<Object>` is unchecked because run-time erasure cannot verify its element type; adding an `Integer` through that view can break an underlying `List<String>`. Treat unchecked-cast warnings as risks to investigate, not as proof that every cast is wrong. section 5.3.2 section 5.3.1

Prefer preserving generic information rather than escaping it:

  • Declare the element type at creation and at API boundaries, such as `List<String>` rather than `List` or broadly permissive `List<Object>`. section 5.3.2 section 8.2
  • Use bounded wildcards when an API only needs a compatible view: `List<? extends CharSequence>` can accept a `List<String>` without an unchecked cast. section 5.3.2
  • Use a generic type parameter when refactoring an `Object`-based interface; raw implementations may keep compiling during an incremental migration, but warnings identify remaining work. section 5.3.1
  • For collections that must be checked while running, consider a checked collection wrapper; it rejects an invalid insertion at the mutation point instead of allowing a later cast failure. section 5.3.2

`List<Object>` is not a raw type, but it often has a similar practical hazard: it permits unrelated values, including nested collections. If only a closed family of alternatives is valid, model that family with a shared interface or sealed interface instead of accepting arbitrary `Object` values. section 8.2 section 8.2

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Explains erasure, compiler-inserted casts, unchecked generic casts, bounded wildcards, and checked collection wrappers.
Examples
Uses a raw List holding an Integer and a corrupted List<String> reached through an unchecked List<Object> cast.
What it assumes
Assumes familiarity with Java collections and casts while explaining generic erasure and implicit casts directly.
What you can do after
Diagnose/debug with it by locating raw declarations or unchecked casts that admit values incompatible with later generic reads.
How it connects
Connects raw types to generics, type erasure, unchecked casts, wildcards, ClassCastException, and List<Object>.

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.