Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: added labels & places where code fails, emits warnings or doesn't comile

...

Code Block
bgColor#FFCCCC
class ListUtility {
  private static void addToList(List list, Object obj) {
    list.add(obj); // unchecked warning
  }

  public static void main(String[] args) {
    List<String> list = new ArrayList<String> ();
    addToList(list, 1);
    System.out.println(list.get(0));  // throws ClassCastException
  }
}

When executed, this code throws an exception. This happens not because a List<String> receives an Integer but because the value returned by list.get(0) is an improper type (an Integer rather than a String). In other words, the code throws an exception some time after the execution of the operation that actually caused the error, complicating debugging.

...

Suppose that the addToList() method was is legacy code that could not cannot be changed. The following compliant solution creates a checked view of the list by using the Collections.checkedList() method. This method returns a wrapper collection that performs runtime type checking in its implementation of the add() method before delegating to the backend List<String>. The wrapper collection can be safely passed to the legacy addToList() method.

Code Block
bgColor#ccccff
class ListUtility {
  private static void addToList(List list, Object obj) {
    list.add(obj); // Unchecked warning, also throws ClassCastException
  }

  public static void main(String[] args) {
    List<String> list = new ArrayList<String> ();
    List<String> checkedList = Collections.checkedList(list, String.class);
    addToList(checkedList, 1);
    System.out.println(list.get(0));
  }
}

...

Code Block
bgColor#FFCCCC
class ListAdder {
  @SuppressWarnings("unchecked")
  private static void addToList(List list, Object obj) {
    list.add(obj);     // Uncheckedunchecked warning suppressed
  }

  private static <T> void printOne(T type) {
    if (!(type instanceof Integer || type instanceof Double)) {
      System.out.println("Cannot print in the supplied type");
    }
    List<T> list = new ArrayList<T>();
    addToList(list, 1);
    System.out.println(list.get(0));
  }

  public static void main(String[] args) {
    double d = 1;
    int i = 1;
    System.out.println(d);
    ListAdder.printOne(d);
    System.out.println(i);
    ListAdder.printOne(i);
  }
}

However, despite list being correctly parameterized, this method prints 1 and never 1.0 because the int value 1 is always added to list without being type checked. This code produces the following output:

Code Block
1.0
1
1
1

Compliant

...

Solution (Parameterized Collection)

This compliant solution generifies the addToList() method, eliminating any possible type violations.

Code Block
bgColor#ccccff
class ListAdder {
  private static <T> void addToList(List<T> list, T t) {
    list.add(t);     // No warning generated
  }

  private static <T> void printOne(T type) {
    if (type instanceof Integer) {
      List<Integer> list = new ArrayList<Integer>();
      addToList(list, 1);
      System.out.println(list.get(0));
    }
    else if (type instanceof Double) {
      List<Double> list = new ArrayList<Double>();

      // This will not compile if addToList(list, 1.0);  is// used
will not compile with 1 instead addToList(list,of 1.0);

      System.out.println(list.get(0));
    }
    else {
      System.out.println("Cannot print in the supplied type");
    }
  }

  public static void main(String[] args) {
    double d = 1;
    int i = 1;
    System.out.println(d);
    ListAdder.printOne(d);
    System.out.println(i);
    ListAdder.printOne(i);
  }
}

This code compiles cleanly and produces the correct output:

Code Block
1.0
1.0
1
1

If the method addToList() is externally defined (such as in a library or as an upcall method) and cannot be changed, the same compliant method printOne() can be used, but no warnings result if addToList(list, 1) is used instead of addToList(list, 1.0). Great care must be taken to ensure type safety when generics are mixed with nongeneric code.

...