Raw Types in Java

Naveen AnamaneniUpdated · 3 min read
mediumJava 25javagenericslegacy

When generics arrived in Java 5, millions of lines of existing code used plain List and Map. To keep all that code compiling, Java allowed generic types to be used without type arguments. A raw type is exactly that: List instead of List<String>. Raw types switch off generic type checking for that variable, so they bring back the runtime bugs generics were designed to remove.

What a Raw Type Allows

Raw.java
import java.util.ArrayList;
import java.util.List;
 
public class Raw {
    public static void main(String[] args) {
        List names = new ArrayList();
        names.add("Navika");
        names.add(42);
        for (Object o : names) {
            String s = (String) o;
            System.out.println(s.toUpperCase());
        }
    }
}

Compiling it gives only a gentle note:

Compiler output
Note: Raw.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

With -Xlint:unchecked, the compiler explains each risky line:

Compiler output (javac -Xlint:unchecked, trimmed)
Raw.java:7: warning: [unchecked] unchecked call to add(E) as a member of the raw type List
        names.add("Navika");
                 ^
  where E is a type-variable:
    E extends Object declared in interface List

And running it crashes, far from the real mistake on line 8:

Terminal output
NAVIKA
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
    at Raw.main(Raw.java:10)

Raw vs <Object> vs <?>

These three look similar but mean different things:

TypeAccepts which lists?Can add?Type checking
List (raw)Any listAnything, with a warningOff
List<Object>Only List<Object>Any objectOn
List<?>Any listNothing (except null)On

If you want "a list of anything" as a parameter, use List<?>; it's as flexible as the raw type but keeps the compiler on your side.

Where Raw Names Are Fine

Some places can't take type arguments at all, so the raw name is correct there:

PlaceExample
Class literalsList.class (not List<String>.class)
instanceof without a pattern variableobj instanceof List (or List<?>)
Importsimport java.util.List;

Common Mistakes

Forgetting <> when creating objects: new ArrayList(). Use new ArrayList<>().

Implementing raw interfaces: implements Comparable. Write implements Comparable<Student>.

Ignoring "uses unchecked or unsafe operations". Recompile with -Xlint:unchecked and fix each warning.

Practice

  1. Easy: Fix Raw.java by adding type arguments. What happens to the names.add(42) line?
  2. Harder: Write a method that takes a raw List and returns its size, then change it to take List<?>. Show that both accept a List<String> and a List<Integer>.

Quick check: Raw types

4 questions
1What is a raw type?
2Why do raw types still exist?
3What should replace a raw List parameter that accepts any list?

Was this tutorial helpful?

Lesson 247 of 482