...
This noncompliant code example declares sums a set of numbers using a variable arity method using Object
. It accepts an arbitrary mix of parameters of any object type. Legitimate uses of such declarations are rare (but see below in the "Applicability" section).
Code Block | ||
---|---|---|
| ||
ReturnTypedouble methodsum(Object... args) { double result = 0.0; for (Object arg : args) { if (arg instanceof Byte) { result += ((Byte) arg).byteValue(); } else if (arg instanceof Short) { result += ((Short) arg).shortValue(); } else if (arg instanceof Integer) { result += ((Integer) arg).intValue(); } else if (arg instanceof Long) { result += ((Long) arg).longValue(); } else if (arg instanceof Float) { result += ((Float) arg).floatValue(); } else if (arg instanceof Double) { result += ((Double) arg).doubleValue(); } else { throw new ClassCastException(); } } return result; } |
Noncompliant Code Example (Generic Type)
This noncompliant code example declares a the same variable arity method using a generic type parameter. It accepts a variable number of parameters that are all of the same object type; however that may be any object type. Again, legitimate uses of such declarations are rare.
Code Block | ||
---|---|---|
| ||
<T> ReturnTypedouble methodsum(T... args) { // ... } |
Compliant Solution
This compliant solution defines the same method, but uses the Number
type. This abstract class is general enough to encompass all numeric types, yet specific enough to exclude non-numeric types.
Code Block | ||
---|---|---|
| ||
double sum(Number... args) {
// ...
} |
Compliant Solution (generic)
This compliant solution defines the same generic method using the Number
typeBe as specific as possible when declaring parameter types; avoid Object
and imprecise generic types in variable arity methods.
Code Block | ||
---|---|---|
| ||
ReturnType method(SpecificObjectType<T extends Number> double sum(T... args) { // ... } |
Be as specific as possible when declaring parameter types; avoid Object
and imprecise generic types in variable arity methods. Retrofitting Retrofitting old methods containing final array parameters with generically typed variable arity parameters is not always a good idea. For example, given a method that does not accept an argument of a particular type, it could be possible to override the compile-time checking—through the use of generic variable arity parameters—so that the method would compile cleanly rather than correctly, causing a runtime error [Bloch 2008].
Also, note that autoboxing prevents strong compile-time type checking of primitive types and their corresponding wrapper classes. For instance, this compliant solution producues the following warning, but works as expected:
Java.java:10: warning: [unchecked] Possible heap pollution from parameterized vararg type T
<T extends Number> double sum(T... args) {
Applicability
Injudicious use of variable arity parameter types prevents strong compile-time type checking, creates ambiguity, and diminishes code readability.
Variable arity signatures using Object
and imprecise generic types are acceptable when the body of the method lacks both casts and auto-boxing, and also compiles without error. Consider the following example, which operates correctly for all object types and type-checks successfully:
Code Block | ||
---|---|---|
| ||
<T> Collection<T> assembleCollection(T... args) { Collection<T> result =return new HashSet<T>(Arrays.asList( args)); // Add each argument to the result collection return result; } |
In some circumstances, it is necessary to use a variable arity parameter of type Object
. A good example of this is the method java.util.Formatter.format(String format, Object... args)
which can format objects of any type.
...