Item 23 - Don’t use raw types in new code

From Effective Java 2/e by Joshua Bloch

Terms

Term Example Item
Parameterized type List<String> Item 23
Actual type parameter String Item 23
Generic type List<E> Item 23, 26
Formal type parameter E Item 23
Unbounded wildcard type List<?> Item 23
Raw type List Item 23
Bounded type parameter List<E extends Number> Item 26
Recursive type bound List<T extends Comparable<T>> Item 27
Bounded wildcard type List<? extends Number> Item 28
Generic method static E List asList(E[] a) Item 27
Type token String.class Item 29

Generic Convention

  • T is meant to be a Type
  • E is meant to be an Element (List<E>: a list of Elements)
  • K is Key (in a Map<K,V>)
  • V is Value (as a return value or mapped value)

Advantages of Generic and Parameterized type

  1. Suggest type-safe way to implement codes
  2. Warning on compile time
  3. No longer have to cast manually when getting elements from collections

generic type information is erased at runtime
Ray type are provided only for compatibility and interoperability with legacy code that predates the introduction of generics

Raw type

/**
 * My stamp collection. Contains only Stamp instances.
 */
private Collection stamps = ... ;

// Erroneous insertion of coin into stamp collection
stamps.add(new Coin( ... ));

// Now a raw iterator type - don't do this!
for (Iterator i = stamps.iterator(); i.hasNext();) {
   Stamp s = (Stamp) i.next(); // Throws ClassCastException
   ... // Do something with the stamp
}

Parameterized type

List<String> strings  = new List<String>();
strings.add(new String());

// for-each loop over a parameterized collection - typesafe
for (Stamp s : stamps) { // No cast
   ... // Do something with the stamp
}

// for loop with parameterized iterator declaration - typesafe
for (Iterator<Stamp> i = stamps.iterator(); i.hasNext(); ) {
   Stamp s = i.next(); // No cast necessary
   ... // Do something with the stamp
}

List v/s List<Object>

  • List has opted out of generic type checking
  • List<Object> has explicitly told the compiler that it is capable of holding objects of any type
// Uses raw type (List) - fails at runtime!
public static void main(String[] args) {
   List<String> strings = new ArrayList<String>();
   unsafeAdd(strings, new Integer(42));
   String s = strings.get(0); // Compiler-generated cast
}

// warning: unchecked call to add(E) in raw type List
private static void unsafeAdd(List list, Object o) {
   list.add(o);
}

// unsafeAdd(List<Object>,Object) cannot be applied to (List<String>,Integer)
private static void unsafeAdd(List<Object> list, Object o) {
   list.add(o);
}

// Parameterized type
private static void safeAdd(List<String> list, String s) {
   list.add(s);
}

// Generic method
private static <E> void safeAdd(List<E> list, E e) {
   list.add(e);
}

Unbounded wildcard type

// Use of raw type for unknown element type - don't do this!
static int numElementsInCommon(Set s1, Set s2) {
   int result = 0;
   for (Object o1 : s1)
      if (s2.contains(o1))
         result++;
   return result;
}

// Unbounded wildcard type - typesafe and flexible
static int numElementsInCommon(Set<?> s1, Set<?> s2) {
   int result = 0;
   for (Object o1 : s1)
      if (s2.contains(o1))
         result++;
   return result;
}

List<?> v/s List<? extends Number>

  • Only null can be added to List<?>
  • Number or Object extending Number can be added to List<? extends Number>

Posted by The Finest Artist