...
Wiki Markup Note that this does not imply that heap pollution only occurs if an unchecked warning actually occurred. It is possible to run a program where some of the binaries were compiled by a compiler for an older version of the Java programming language, or by a compiler that allows the unchecked warnings to suppressed _\[sic\]_. This practice is unhealthy at best.
Overriding Extending legacy classes and generifying the overriding method methods is not a panacea as this is made illegal by the Java Language Specification [JLS 05]. It is best to avoid mixing generic and non-generic code.
...
When executed, this code produces an exception because the value returned by list.get(0)
is not of the proper type. , that is, String
:
Code Block |
---|
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at Raw.print(Test.java:11) at Raw.main(Test.java:14) |
...
By gleaning information from the diagnostic exception message, the error can be quickly traced to the line addToList(1)
in the noncompliant code example. Changing this to addToList("1")
is unfortunately a superficial defense. To resolve the real issue, use parameterized types must be used consistently and not just abundantly.
To enforce compile time checking of types, replace the parameters to the method addToList()
with List<String> list
and String str
. The compiler does not allow insertion of an Object
once list
is parameterized. Likewise, addToList()
cannot be called with an argument whose type produces a mismatch.
Code Block | ||
---|---|---|
| ||
class Parameterized { private static void addToList(List<String> list, String str) { list.add(str); // 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(); } } |
The compiler does not allow insertion of an Object
once list
is parameterized. Likewise, addToList()
cannot be called with an argument whose type produces a mismatch.
Noncompliant Code Example
This noncompliant code example suffers from related pitfalls. It compiles and runs cleanly. The method printOne()
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 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); } } |
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 output:
Code Block |
---|
1.0 1 1 1 |
Compliant Solution
If possible, This compliant solution generifies the addToList()
method should be generified to eliminate possible type violations.
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); } } |
...