Item 26: Don’t use raw types
If you use raw types, you lose all the safety and expressiveness benefits of generics
the raw type List and the parameterized type List<Object>
Set<E>
is Set<?>
(read “set of some type”)
List<String>
(read “list of string”)
String is the actual type parameter corresponding to the formal type parameter E.
the raw type corresponding to List<E>
is List
it pays to discover errors as soon as possible after they are made, ideally at compile time. In this case, you don’t discover the error until runtime, long after it has happened, and in code that may be distant from the code containing the error. Once you see the ClassCastException, you have to search through the codebase looking for the method invocation that put the coin into the stamp collection
you lose type safety if you use a raw type such as List, but not if you use a parameterized type such as List<Object>.
a few minor exceptions to the rule that you should not use raw types:
You must use raw types in class literals.
List.class, String[].class, and int.class
wildcard type Set<?>
using raw types can lead to exceptions at runtime, so don’t use them
Term | Example | Item |
---|---|---|
Parameterized type | List<String> | Item-26 |
Actual type parameter | String | Item-26 |
Generic type | List<E> | Item-26, Item-29 |
Formal type parameter | E | Item-26 |
Unbounded wildcard type | List<?> | Item-26 |
Raw type | List | Item-26 |
Bounded type parameter | <E extends Number> | Item-29 |
Recursive type bound | <T extends Comparable<T>> | Item-30 |
Bounded wildcard type | List<? extends Number> | Item-31 |
Generic method | static <E> List<E> asList(E[] a) | Item-30 |
Type token | String.class | Item-33 |
Item 27: Eliminate unchecked warnings
unchecked cast warnings,
unchecked method invocation warnings,
unchecked parameterized vararg type warnings,
and unchecked conversion warnings
Set<Lark> exaltation = new HashSet(); Venery.java:4: warning: [unchecked] unchecked conversion Set<Lark> exaltation = new HashSet(); ^ required: Set<Lark> found: HashSet diamond operator (<>) Set<Lark> exaltation = new HashSet<>();
Eliminate every unchecked warning that you can
If you can’t eliminate a warning, but you can prove that the code that provoked the warning is typesafe, then (and only then) suppress the warning with an @SuppressWarnings("unchecked") annotation.
Always use the SuppressWarnings annotation on the smallest scope possible.
public <T> T[] toArray(T[] a) { if (a.length < size) return (T[]) Arrays.copyOf(elements, size, a.getClass()); System.arraycopy(elements, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } ArrayList.java:305: warning: [unchecked] unchecked cast return (T[]) Arrays.copyOf(elements, size, a.getClass()); ^ required: T[] found: Object[] // Adding local variable to reduce scope of @SuppressWarnings public <T> T[] toArray(T[] a) { if (a.length < size) { // This cast is correct because the array we're creating // is of the same type as the one passed in, which is T[]. @SuppressWarnings("unchecked") T[] result = (T[]) Arrays.copyOf(elements, size, a.getClass()); return result; } System.arraycopy(elements, 0, a, 0, size); if (a.length > size) a[size] = null; return a; }
Every time you use a @SuppressWarnings("unchecked") annotation, add a comment saying why it is safe to do so.