Warm-up

Watch an array fail where a list would not

5 minjunior16 yrs

One concept, guided. Near-impossible to fail.

What this teaches

  • Arrays are covariant, so a wrong store compiles and throws at runtime
  • Generics are invariant, so the same mistake is a compile error
  • The two rules are not an inconsistency — they are two answers to the same question

Starter

Starter.javaOpen in playground
import java.util.*;

/**
 * WARM-UP — 5 minutes. One concept. Hard to fail.
 *
 * The same mistake, twice: once with an array and once with a list. Java
 * catches it at two completely different moments.
 *
 * TASKS
 *   1. Predict what happens at each numbered line before running.
 *   2. Run it. Which line threw, and which line was fine?
 *   3. Uncomment block (3) and compile. Read the error.
 *   4. In a comment: the array version compiles and throws; the list version
 *      does not compile. Which would you rather ship, and why?
 */
public class Starter {
    public static void main(String[] args) {
        String[] names = {"ravi", "anita"};

        // (1) Legal — arrays are covariant. A String[] IS an Object[].
        Object[] asObjects = names;
        System.out.println("aliased an Object[] onto a String[] : ok");

        // (2) Compiles. Does it run?
        try {
            asObjects[0] = 42;
            System.out.println("stored an Integer                   : ok");
        } catch (ArrayStoreException e) {
            System.out.println("stored an Integer                   : "
                    + e.getClass().getSimpleName() + ": " + e.getMessage());
        }

        // (3) Uncomment these two lines. They will not compile.
        // List<String> nameList = new ArrayList<>(List.of("ravi", "anita"));
        // List<Object> asObjectList = nameList;

        System.out.println();
        System.out.println("reads are always fine, in both worlds:");
        for (Object each : asObjects) {
            System.out.println("  " + each);
        }

        // Question to answer in a comment before you move on:
        // Every array store in every Java program pays for a check that makes
        // line (2) throw. What does the generic version pay at runtime?
    }
}

Run it locally:

cd exercises/java/generics/generics-variance/01-warmup
javac Starter.java -d /tmp/out && java -cp /tmp/out Starter

Done when

  • You predicted where the ArrayStoreException would land before running
  • The generic version is uncommented, its error read, and commented back out
  • A comment says which of the two you would rather have on a Friday afternoon

← Back to Why is List<String> not a List<Object>?