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
- Suggest type-safe way to implement codes
- Warning on compile time
- 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>