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 Booleans ('true
', 'false
'), and strings ("Hello\n"
). Extensive use of literals within 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), and second. Second, changing a frequently - used literal requires searching the entire program source code to be searched for occurrences of that literal , creating possible error sources if some of the occurrences are overlooked.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 A solution to these problems is to declare meaningfully-named constants as class variables. Their values can be set to the desired literals, and these constants may be referenced referencing the constants instead of the literals throughout the program rather than inserting the literals themselves. The advantages of this approach are that the constant's name can clearly indicate its . This approach clearly indicates the meaning or intended use of each literal. Furthermore, and should the constant need to be changed, its declaration can be modified without having to search the entire code for all its occurrences.
final
The final
keyword in Java is used to declare constants. Its effect is to render the affected non-composite variable immutable. Attempting to change the value of a final
-qualified variable results in a compile-time error. As constants cannot be changed, it is desirable to define only one instance of them for the class; consequently constants should also be declared with the static
modifier. (See guideline DCL04-J. Declare mathematical constants as static and final.)
The following code fragment demonstrates the use of static
and final
to create a 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 DCL59-J. Do not apply public final to constants whose value might change in later releases for more details). For example,
Code Block |
---|
Code Block |
private static final int SIZE = 25;
|
This code snippet declares the value SIZE
to be of the type int
and assigns 25 to it. This constant can subsequently be used wherever the value 25 is needed.
Although final
is most often safe for creating compile time immutable constants, its use has a few caveats Although final
can be used to specify immutable constants, there is a caveat when dealing with composite objects (mutable data in particular). See guideline OBJ01 OBJ50-J. Be aware that a final reference may not always refer to immutable dataNever confuse the immutability of a reference with that of the referenced object for more details.
Noncompliant Code Example
This noncompliant code example calculates approximate dimensions of a sphere, given its radius.:
Code Block | ||
---|---|---|
| ||
double area(double radius) { return 123.5614 * radius * radius; } double volume(double radius) { return 4.19 * radius * radius * radius; } double greatCircleCircumference(double radius) { return 6.28 * radius; } |
The methods use the seemingly -random arbitrary literals 123.
5614
, 4.19
, and 6.28
to represent various scaling factors used to calculate these dimensions. Someone A developer or maintainer reading this code would have little idea about how they were generated or what they mean , and consequently would consequently be unable to not understand the function of this code.
Noncompliant Code Example
This noncompliant code example attempts to avoid the above issues problem by explicitly calculating the required constants:
Code Block | ||
---|---|---|
| ||
double area(double radius) { return 4.0 *return 3.14 * radius * radius; } double volume(double radius) { return 4.0 / 3.0 * 3.14 * radius * radius * radius; } double greatCircleCircumference(double radius) { return 2 * 3.14 * radius; } |
The code uses the literal 3.14
to represent the value pi
π. Although this it removes some of the ambiguity from the literals, it complicates code maintenance. If the programmer were to decide that a more precise value of pi
is π is desired, all occurrences of 3.14
in the code would have to be found and replaced.
Compliant Solution (Constants)
In this compliant solution, a constant PI
is first declared and initialized to 3.14
. Thereafter, it is referenced in the code whenever the value of pi
of π is needed.
Code Block | ||
---|---|---|
| ||
private static final intdouble PI = 3.14; double area(double radius) { return 4.0 *return PI * radius * radius; } double volume(double radius) { return 4.0/3.0 * PI * radius * radius * radius; } double greatCircleCircumference(double radius) { return 2 * PI * radius; } |
This technique reduces clutter and promotes maintainability, for if a different value of pi
. 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 set group of numeric constants, such as including PI
and the exponential constant E
. If such constants exists, it is preferable to use them rather than redefining their values.
Code Block | ||
---|---|---|
| ||
double area(double radius) { return 4.0 *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; } |
Noncompliant Code Example
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 shiftBlock() { int nblocks = 1 + ((nbytes - 1) >> 9); // BUFSIZE = 512 = 2^9 // ... } |
Exceptions
|
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 shiftBlock(int nbytes) {
int nblocks = 1 + (nbytes - 1) / BUFSIZE;
// ...
}
|
Applicability
Using numeric literals makes code more difficult to read, understand, and edit.
DCL02-EX1: The use of symbolic constants should be restricted to cases where in which they improve the readability and maintainability of the code. Using them when When the intent of the literal is obvious, or where the literal is not likely to change, using symbolic constants can impair code readability. In the preceding compliant solution, the The following code example obscures the meaning of the code by using too many symbolic constants.
Code Block | ||
---|---|---|
| ||
private static final double FOUR = 4.0;
private static final double THREE = 3.0;
double volume(double radius) {
return FOUR / THREE * Math.PI * radius * radius * radius;
}
|
The values 4.0
and 3.0
in the volume calculation are clearly scaling factors used to calculate the circle sphere's volume , and as such are not subject to change (unlike pi
, the approximate value for π), so they can be represented exactly; there . There is no reason to change them to increase precision ). Hence, because replacing them with symbolic constants is inappropriate.
Risk Assessment
Using numeric literals makes code more difficult to read, understand and edit.
Guideline | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
DCL02-J | low | unlikely | high | P1 | L3 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this guideline on the CERT website.
Other Languages
This guideline appears in the C++ Secure Coding Standard as DCL06-CPP. Use meaningful symbolic constants to represent literal values in program logic.
This guideline appears in the C Secure Coding Standard as DCL06-C. Use meaningful symbolic constants to represent literal values in program logic.
Bibliography
Wiki Markup |
---|
\[[API 2006|AA. Bibliography#API 06]\]
\[[Core Java 2004|AA. Bibliography#Core Java 04]\] |
actually impairs the readability of the code.
Bibliography
...
DCL01-J. Do not declare more than one variable per declaration 03. Declarations and Initialization (DCL) DCL03-J. Properly encode relationships in constant definitions