...
According to the Java Language Specification (JLS) §4.2.2, "Integer Operations,"
If an integer operator other than a shift operator has at least one operand of type
long, then the operation is carried out using 64-bit precision, and the result of the numerical operator is of typelong. If the other operand is notlong, it is first widened (§5.1.5) to typelongby numeric promotion (§5.6). Otherwise, the operation is carried out using 32-bit precision, and the result of the numerical operator is of typeint. If either operand is not anint, it is first widened to typeintby numeric promotion.
...
The JLS §5.6, "Numeric Promotions," describes numeric promotion as the following:
...
Widening conversions, resulting from integer promotions, preserves the overall magnitude of the number. However, promotions in which the operands are converted from an int to a float or from a long to a double can cause unexpected loss of precision. (See guideline "NUM17-J. Beware of precision loss when converting primitive integers to floating-point" for more details.)
These conversions can happen with the following operators: multiplicative operators (%, *, /), additive operators (+, -), comparison operators (<, >, <=, >=), equality operators (==, !=), and the integer bitwise operators (&, |, ^).
...
According to the JLS §15.26.2, "Compound Assignment Operators,"
A compound assignment expression of the form
E1 op= E2is equivalent toE1 = (T)((E1) op (E2)), whereTis the type ofE1, except thatE1is evaluated only once.
...
In this noncompliant code example, a variable of type int (big) is multiplied by a value of type float one. In this case, numeric promotions require that big is promoted to the type float before the multiplication occurs, resulting in loss of precision. (See guideline "NUM17-J. Beware of precision loss when converting primitive integers to floating-point".)
| Code Block | ||
|---|---|---|
| ||
class Test{
public static void main(String[] args){
int big = 1999999999;
float one = 1.0f;
// binary operation, loses precision because of implicit cast
System.out.println(big * one);
}
}
|
...
| Code Block | ||
|---|---|---|
| ||
class Test{
public static void main(String[] args){
int big = 1999999999;
double one = 1.0d; // double instead of float
System.out.println(big*one);
}
}
|
This solution produces the expected output of 1.999999999E9. This , which is the value that is obtained when an int is assigned (implicitly cast) to a double.
...
| Code Block | ||
|---|---|---|
| ||
int result = 0; for (int i = 0; i < 4; i++) result = ((result << 8) | (b[i] & 0xff)); |
Noncompliant Code Example (Compound Addition
...
and Assignment)
This noncompliant code example performs a compound assignment operation. This operation involves an int value that contains too many significant bits to fit in the twenty23-three bit mantissa of a Java float, causing the widening conversion from int to float to lose precision. The resulting value could surprise many programmers.
| Code Block | ||
|---|---|---|
| ||
public class Expr {
public static void main(String[] args) {
int x = 2147483642; // 0x7ffffffa
x += 1.0f; // x contains 2147483647 (0x7fffffff) after the computation
}
}
|
Compliant Solution (Compound Addition
...
and Assignment)
To be safe, avoid using any of the compound assignment operators on variables of types byte, short, or char. Also, refrain from using a wider operand on the right-hand side. In this compliant solution, all operands are of the Java type double.
| Code Block | ||
|---|---|---|
| ||
public class Expr {
public static void main(String[] args) {
double x = 2147483642; // 0x7ffffffa
x += 1.0; // x contains 2147483643.0 (0x7ffffffb.0) as expected
}
}
|
Noncompliant Code Example (Compound Bit Shift
...
and Assignment)
This noncompliant code example uses a compound right-shift operator for shifting the value of i, bit by bit. Unfortunately, the value of i remains the same. The value of i is first promoted to an int. This is a widening primitive conversion, so no data is lost. With short, -1 is represented as 0xffff. The conversion to int results in the value 0xffffffff, which is right shifted by 1 bit to yield 0x7fffffff. To store the value back into the short variable i, Java then performs an implicit narrowing conversion, discarding the 16 higher order bits. The final result is again 0xffff, or -1.
| Code Block | ||
|---|---|---|
| ||
short i = -1; i >>>= 1; |
Compliant Solution (Compound Bit Shift
...
and Assignment)
This compliant solution applies the compound assignment operator to an int, which does not require widening and subsequent narrowing.
...
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="1b5f3a887bf85836-3adbd6d3-47e34082-8a82adcc-5454b9a35cae387cd359a70f"><ac:plain-text-body><![CDATA[ | [[Bloch 2005 | AA. References#Bloch 05]] | Puzzle 9: "Tweedledum" | ]]></ac:plain-text-body></ac:structured-macro> | |
| Puzzle 31: "Ghost of Looper" | ||||
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="05926b09fc74a50c-60094f1a-4e064282-85c88bb1-ccc69af418b448adf3c90a13"><ac:plain-text-body><![CDATA[ | [[Findbugs 2008 | AA. References#Findbugs 08]] | "BIT: Bitwise OR of signed byte value" | ]]></ac:plain-text-body></ac:structured-macro> | |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="37c2b5179114b54a-9d640c1a-4dc144c7-b93a915a-360071839809559d567538f9"><ac:plain-text-body><![CDATA[ | [[JLS 2005 | AA. References#JLS 05]] | [§4.2.2, "Integer Operations" | http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.2] | ]]></ac:plain-text-body></ac:structured-macro> |
| |||||
|
...