When the compiler detects potential type-safety issues arising from mixing raw types with generic code, it issues unchecked warnings, including unchecked cast warnings, unchecked method invocation warnings, unchecked generic array creation warnings, and unchecked conversion warnings [Bloch 2008]. It is permissible to use the @SuppressWarnings("unchecked")
annotation to suppress unchecked warnings when, and only when, the warning-emitting code is guaranteed to be type safe. A common use case is mixing legacy code with new client code. The perils of ignoring unchecked warnings are discussed extensively in OBJ03-J. Do not mix generic with nongeneric raw types in new code.
According to the Java API, Annotation Type SuppressWarnings
documentation [API 2014],
As a matter of style, programmers should always use this annotation on the most deeply nested element where it is effective. If you want to suppress a warning in a particular method, you should annotate that method rather than its class.
The @SuppressWarnings
annotation can be used in the declaration of variables and methods as well as an entire class. It is, however, important to narrow its scope so that only those warnings that occur in the narrower scope are suppressed.
Noncompliant Code Example
In this noncompliant code example, the @SuppressWarnings
annotation's scope encompasses the whole class:
@SuppressWarnings("unchecked") class Legacy { Set s = new HashSet(); public final void doLogic(int a, char c) { s.add(a); s.add(c); // Type-unsafe operation, ignored } }
This code is dangerous because all unchecked warnings within the class are suppressed. Oversights of this nature can lead to a ClassCastException
at runtime.
Compliant Solution
Limit the scope of the @SuppressWarnings
annotation to the nearest code that generates a warning. In this case, it may be used in the declaration for the Set
:
class Legacy { @SuppressWarnings("unchecked") Set s = new HashSet(); public final void doLogic(int a,char c) { s.add(a); // Produces unchecked warning s.add(c); // Produces unchecked warning } }
Noncompliant Code Example (ArrayList
)
This noncompliant code example is from an old implementation of java.util.ArrayList
:
@SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { if (a.length < size) { // Produces unchecked warning return (T[]) Arrays.copyOf(elements, size, a.getClass()); } // ... }
When the class is compiled, it emits an unchecked cast warning:
// Unchecked cast warning ArrayList.java:305: warning: [unchecked] unchecked cast found : Object[], required: T[] return (T[]) Arrays.copyOf(elements, size, a.getClass());
This warning cannot be suppressed for just the return
statement because it is not a declaration [JLS 2011]. As a result, the programmer suppresses warnings for the entire method. This can cause issues when functionality that performs type-unsafe operations is added to the method at a later date [Bloch 2008].
Compliant Solution (ArrayList
)
When it is impossible to use the @SuppressWarnings
annotation in an appropriate scope, as in the preceding noncompliant code example, declare a new variable to hold the return value and adorn it with the @SuppressWarnings
annotation.
// ... @SuppressWarnings("unchecked") T[] result = (T[]) Arrays.copyOf(elements, size, a.getClass()); return result; // ...
Applicability
Failure to reduce the scope of the @SuppressWarnings
annotation can lead to runtime exceptions and break type-safety guarantees.
This rule cannot be statically enforced in full generality; however, static analysis could be possible for some special cases.
Bibliography
[API 2014] | Annotation Type SuppressWarnings |
[Bloch 2008] | Item 24, "Eliminate Unchecked Warnings" |