Integer variables are frequently intended to represent either a numeric value or a bitmapbit collection. Numeric values should be exclusively operated upon using arithmetic operations, while bitmaps bit collections should be exclusively operated upon using logical operations. However, it is frequently difficult for an analyzer to determine if the intended usage of a particular integer variable.
Performing bitwise and arithmetic operations on the same data does suggest confusion about suggests confusion as to the purpose of the data stored in the variable. Unfortunately, bitwise operations are frequently performed on arithmetic values as a form of premature optimization. Bitwise operators include the unary operator ~ and the binary operators <<
, >>
, &
, ^, and |
. Although such operations are valid and will compile, they can reduce code readability.
Noncompliant Code Example (Left Shift)
Left- and right-shift operators are often employed to multiply or divide a number by a power of 2. This compromises code readability and portability for the sake of often-illusory speed gains. The JVM will usually make such optimizations automatically, and unlike a programmer, the JVM can optimize for the implementation details of the current platform. This is also problematic in that right shifting is not equivalent to division for negative dividends.
Noncompliant Code Example (Left Shift)
In this noncompliant code example, both bit manipulation and arithmetic manipulation are performed on the integer x
that conceptually contains a numeric value. The result is a (prematurely) optimized statement that assigns 5x + 1
to x
.
...
Using logical right shift for division produces an incorrect result when the dividend (x
in this example) contains a negative value. Although left Arithmetic right shift can replace division for non-negative dividends, it :
Code Block | ||
---|---|---|
| ||
int x = -50;
x = x + 2;
x >>>= 2;
|
However, the result is less maintainable than making the division explicit. Refer to guideline NUM04-J. Use shift operators correctly for examples of sign extension with respect to the shift operators.
Compliant Solution (Right Shift)
...
Code Block | ||
---|---|---|
| ||
int x = -50;
x += 2
x /= 4;
|
Noncompliant Code Example
In this noncompliant code example, a programmer is attempting to fetch four values from a byte array and pack them into the the integer variable result
. The integer value in this example represents a bit collection and not a numeric value.
Code Block | ||
---|---|---|
| ||
// b[] is a byte array, initialized to 0xff
byte[4] b {-1, -1, -1, -1};
int result = 0;
for (int i = 0; i < 4; i++) {
result = ((result << 8) + b[i]);
}
|
Wiki Markup |
---|
In performing the bitwise operation, the value of the byte array element {{b\[i\]}} is promoted to an {{int}} by sign-extension. When a byte array element contains a negative value (for example, {{0xff}}), the sign-extension propagates 1-bits into the upper 24 bits of the {{int}}. This behavior may be unexpected if the programmer is assuming that {{byte}} is an unsigned type. In this example, adding the promoted byte values to {{result}} fails to result in a packed integer representation of the bytes \[[Findbugs 2008|AA. Bibliography#Findbugs 08]\]. |
Noncompliant Code Example
This noncompliant code example masks off the upper 24 bits of the promoted byte array element before performing the addition. The number of bits required to mask the sizes of byte
and int
are specified by the JLS. While this code calculates the correct result, it violates this guideline by combining bitwise and arithmetic operations on the same data.
Code Block | ||
---|---|---|
| ||
byte[4] b {-1, -1, -1, -1};
int result = 0;
for (int i = 0; i < 4; i++) {
result = ((result << 8) + (b[i] & 0xff));
}
|
Compliant Solution
This compliant solution masks off the upper 24 bits of the promoted byte array element. The result is then combined with result
using a logical OR operation.
Code Block | ||
---|---|---|
| ||
byte[4] b {-1, -1, -1, -1}; int result = 0; for (int i = 0; i < 4; i++) { result = ((result << 8) | (b[i] & 0xff)); } |
Exceptions
INT03-EX1: Bitwise operations may be used to construct constant expressions.
...