Java supports the use of various types of literals, such as integers (5, 2), floating-point numbers (2.5, 6.022e+23), characters ('a'
, '\n'
), Booleans (true
, false
), and strings ("Hello\n"
). Extensive use of literals in a program can lead to two problems: first. First, the meaning of the literal is often obscured or unclear from the context (magic numbers); second. Second, changing a frequently used literal requires searching the entire program source for that literal and distinguishing the uses that must be modified from those that should remain unmodified.
Avoid these problems by declaring class variables with meaningfully named constants, setting their values to the desired literals, and referencing the constants in place instead of the literals throughout the program. This approach clearly indicates the meaning or intended use of the each literal. FurtherFurthermore, should the constant require modification, the change is limited to the declaration; searching the code is unnecessary.
Constants should be declared as static
and final
. However, constants should not be declared public and final if their values might change (see 31. Do not apply public final to constants whose value might change in later releases for more details). For example,
Code Block |
---|
private static final int SIZE = 25; |
Although final
can be used to specify immutable constants, there is a caveat when dealing with composite objects. SeeOBJ50-J 73. Never confuse the immutability of a reference with that of the referenced object for more details.
Noncompliant Code Example
...
This technique reduces clutter and promotes maintainability. If a more precise approximation of the value of π is required, the programmer can simply redefine the constant. The use of the literals 4.0
, 3.0
, and 2
does not violate this guideline, for reasons explained in the "Applicability" section of this guideline.
Compliant Solution (Predefined Constants)
Use predefined constants when they are available. The class java.lang.Math
defines a large group of numeric constants, including PI
and the exponential constant E
. Use predefined constants when they are available.
Code Block | ||
---|---|---|
| ||
double area(double radius) { return Math.PI * radius * radius; } double volume(double radius) { return 4.0/3.0 * Math.PI * radius * radius * radius; } double greatCircleCircumference(double radius) { return 2 * Math.PI * radius; } |
...
This noncompliant code example defines a constant BUFSIZE
, but then defeats the purpose of defining BUFSIZE
as a constant by assuming a specific value for BUFSIZE
in the following expression:
Code Block | ||
---|---|---|
| ||
private static final int BUFSIZE = 512; // ... public void exampleFunctionshiftBlock() { int nblocks = 1 + ((nbytes - 1) >> 9); // BUFSIZE = 512 = 2^9 // ... } |
The programmer has assumed that BUFSIZE
is 512, and right-shifting 9 bits is the same (for positive numbers) as dividing by 512. However, if BUFSIZE
changes to 1024 in the future, modifications will be difficult and error prone.
This code also fails to conform to NUM01-J. Do not perform bitwise and arithmetic operations on the same data. Replacing a division operation with a right shift is considered a premature optimization. Normally, the compiler will do a better job of determining when this optimization should be performed.
Compliant Solution
This compliant solution uses the identifier assigned to the constant value in the expression:
Code Block | ||
---|---|---|
| ||
private static final int BUFSIZE = 512; // ... public void exampleFunctionshiftBlock(int nbytes) { int nblocks = 1 + (nbytes - 1) / BUFSIZE; // ... } |
...