Generically typed code can be freely used with raw types when attempting to preserve compatibility between non-generic legacy code and newer generic code. However, using raw types with generic code cause causes most Java compilers to issue "unchecked" warnings. When generic and non-generic types are used together correctly, these warnings are not catastrophic, but at other times, these warnings may denote potentially unsafe operations. If generic and non-generic code must be used together, these warnings should not be simply ignored.
...
Code Block |
---|
List l = new ArrayList<Integer>(); List<String> ls = l; // producesProduces unchecked warning |
However, to implement this guideline unchecked warnings cannot not be relied upon. According to the Java Language Specification [JLS 05] section 4.12.2.1 "Heap Pollution":
...
Noncompliant Code Example
This noncompliant code example produces an unchecked warning because the raw type of the List.add()
method is used (the list
parameter in addToList()
method) instead of the parameterized type. To make this code compile cleanly, the @SuppressWarnings
annotation is used.
Code Block | ||
---|---|---|
| ||
public class MixedTypes { @SuppressWarnings("unchecked") private static void addToList(List list, Object obj) { list.add(obj); // "unchecked"Unchecked warning } private static void print() { List<String> list = new ArrayList<String> (); addToList(list, 1); System.out.println(list.get(0)); } public static void main(String[] args) { MixedTypes.print(); } } |
...
Code Block | ||
---|---|---|
| ||
class Parameterized { private static void addToList(List<String> list, String str) { list.add(str); // "unchecked"Unchecked warning } private static void print() { List<String> list = new ArrayList<String> (); addToList(list, "1"); System.out.println(list.get(0)); } public static void main(String[] args) { Parameterized.print(); } } |
Noncompliant Code Example
This noncompliant code example suffers from related pitfalls. It compiles and runs cleanly. The method printOne
is intended ()
intends to print the value one, either as an int
or as a double
depending on the type of the variable type
. However, despite list
being correctly parameterized, this method always print '1' and never '1.0' because the int
value '1' is always added to list
without being type checked.
Code Block | ||
---|---|---|
| ||
class BadListAdder { @SuppressWarnings("unchecked") private static void addToList(List list, Object obj) { list.add(obj); // "unchecked"Unchecked warning } 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); BadListAdder.printOne(d); System.out.println(i); BadListAdder.printOne(i); } } |
...
Code Block | ||
---|---|---|
| ||
class GoodListAdder { private static void addToList(List<Integer> list, Integer i) { list.add(i); } private static void addToList(List<Double> list, Double d) { list.add(d); } 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) is used addToList(list, 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); GoodListAdder.printOne(d); System.out.println(i); GoodListAdder.printOne(i); } } |
...