All compound assignment operators require both operands to be of primitive type,
except for +=
, which allows the right-hand operand to be of any type if the left-
hand operand is of type String
.
A compound assignment expression of the form E1 op= E2 is equivalent to E1 =
(
T)((
E1)
op (
E2))
, where T is the type of E1, except that E1 is evaluated only once. Note that the implied cast to type T may be either an identity conversion (§5.1.1) or a narrowing primitive conversion (§5.1.3). For example, the following code is correct:
short x = 3; x += 4.6;
and results in x
having the value 7
because it is equivalent to:
short x = 3; x = (short)(x + 4.6);
At run time, the expression is evaluated in one of two ways. If the left-hand operand expression is not an array access expression, then four steps are required:
If the left-hand operand expression is an array access expression (§15.12), then many steps are required:
null
, then no assignment occurs and a NullPointerException
is thrown.
IndexOutOfBoundsException
is thrown.
String
. Because class String
is a final
class, S must also be String
. Therefore the run-time check that is sometimes required for the simple assignment operator is never required for a compound assignment operator.
+=
). If this operation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.
String
result of the binary operation is stored into the array component.
The rules for compound assignment to an array component are illustrated by the following example program:
class ArrayReferenceThrow extends RuntimeException { }
class IndexThrow extends RuntimeException { }
class RightHandSideThrow extends RuntimeException { }
class IllustrateCompoundArrayAssignment {
static String[] strings = { "Simon", "Garfunkel" };
static double[] doubles = { Math.E, Math.PI };
static String[] stringsThrow() { throw new ArrayReferenceThrow(); }
static double[] doublesThrow() { throw new ArrayReferenceThrow(); }
static int indexThrow() { throw new IndexThrow(); }
static String stringThrow() { throw new RightHandSideThrow(); }
static double doubleThrow() { throw new RightHandSideThrow(); }
static String name(Object q) { String sq = q.getClass().getName(); int k = sq.lastIndexOf('.'); return (k < 0) ? sq : sq.substring(k+1); }
static void testEight(String[] x, double[] z, int j) { String sx = (x == null) ? "null" : "Strings"; String sz = (z == null) ? "null" : "doubles"; System.out.println(); try { System.out.print(sx + "[throw]+=throw => "); x[indexThrow()] += stringThrow(); System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } try { System.out.print(sz + "[throw]+=throw => "); z[indexThrow()] += doubleThrow(); System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } try { System.out.print(sx + "[throw]+=\"heh\" => "); x[indexThrow()] += "heh"; System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } try { System.out.print(sz + "[throw]+=12345 => "); z[indexThrow()] += 12345; System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } try { System.out.print(sx + "[" + j + "]+=throw => "); x[j] += stringThrow(); System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } try { System.out.print(sz + "[" + j + "]+=throw => "); z[j] += doubleThrow(); System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } try { System.out.print(sx + "[" + j + "]+=\"heh\" => "); x[j] += "heh"; System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } try { System.out.print(sz + "[" + j + "]+=12345 => "); z[j] += 12345; System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } }
public static void main(String[] args) { try { System.out.print("throw[throw]+=throw => "); stringsThrow()[indexThrow()] += stringThrow(); System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } try { System.out.print("throw[throw]+=throw => "); doublesThrow()[indexThrow()] += doubleThrow(); System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } try { System.out.print("throw[throw]+=\"heh\" => "); stringsThrow()[indexThrow()] += "heh"; System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); }
try { System.out.print("throw[throw]+=12345 => "); doublesThrow()[indexThrow()] += 12345; System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } try { System.out.print("throw[1]+=throw => "); stringsThrow()[1] += stringThrow(); System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } try { System.out.print("throw[1]+=throw => "); doublesThrow()[1] += doubleThrow(); System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } try { System.out.print("throw[1]+=\"heh\" => "); stringsThrow()[1] += "heh"; System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } try { System.out.print("throw[1]+=12345 => "); doublesThrow()[1] += 12345; System.out.println("Okay!"); } catch (Throwable e) { System.out.println(name(e)); } testEight(null, null, 1); testEight(null, null, 9); testEight(strings, doubles, 1); testEight(strings, doubles, 9); }
}
throw[throw]+=throw => ArrayReferenceThrow throw[throw]+=throw => ArrayReferenceThrow throw[throw]+="heh" => ArrayReferenceThrow throw[throw]+=12345 => ArrayReferenceThrow throw[1]+=throw => ArrayReferenceThrow throw[1]+=throw => ArrayReferenceThrow throw[1]+="heh" => ArrayReferenceThrow throw[1]+=12345 => ArrayReferenceThrow
null[throw]+=throw => IndexThrow null[throw]+=throw => IndexThrow null[throw]+="heh" => IndexThrow null[throw]+=12345 => IndexThrow null[1]+=throw => NullPointerException null[1]+=throw => NullPointerException null[1]+="heh" => NullPointerException null[1]+=12345 => NullPointerException
null[throw]+=throw => IndexThrow null[throw]+=throw => IndexThrow null[throw]+="heh" => IndexThrow null[throw]+=12345 => IndexThrow null[9]+=throw => NullPointerException null[9]+=throw => NullPointerException null[9]+="heh" => NullPointerException null[9]+=12345 => NullPointerException
Strings[throw]+=throw => IndexThrow doubles[throw]+=throw => IndexThrow Strings[throw]+="heh" => IndexThrow doubles[throw]+=12345 => IndexThrow Strings[1]+=throw => RightHandSideThrow doubles[1]+=throw => RightHandSideThrow Strings[1]+="heh" => Okay! doubles[1]+=12345 => Okay!
Strings[throw]+=throw => IndexThrow doubles[throw]+=throw => IndexThrow Strings[throw]+="heh" => IndexThrow doubles[throw]+=12345 => IndexThrow Strings[9]+=throw => IndexOutOfBoundsException doubles[9]+=throw => IndexOutOfBoundsException Strings[9]+="heh" => IndexOutOfBoundsException doubles[9]+=12345 => IndexOutOfBoundsException
The most interesting cases of the lot are tenth and eleventh from the end:
Strings[1]+=throw => RightHandSideThrow doubles[1]+=throw => RightHandSideThrow
They are the cases where a right-hand side that throws an exception actually gets to throw the exception; moreover, they are the only such cases in the lot. This demonstrates that the evaluation of the right-hand operand indeed occurs after the checks for a null array reference value and an out-of-bounds index value.
The following program illustrates the fact that the value of the left-hand side of a compound assignment is saved before the right-hand side is evaluated:
class Test { public static void main(String[] args) { int k = 1; int[] a = { 1 }; k += (k = 4) * (k + 2); a[0] += (a[0] = 4) * (a[0] + 2); System.out.println("k==" + k + " and a[0]==" + a[0]); } }
k==25 and a[0]==25
The value 1
of k
is saved by the compound assignment operator +=
before its
right-hand operand (k
=
4)
*
(k
+
2)
is evaluated. Evaluation of this right-hand
operand then assigns 4
to k
, calculates the value 6
for k
+
2
, and then multiplies
4
by 6
to get 24
. This is added to the saved value 1
to get 25
, which is then stored
into k
by the +=
operator. An identical analysis applies to the case that uses a[0]
.
In short, the statements
k += (k = 4) * (k + 2); a[0] += (a[0] = 4) * (a[0] + 2);
behave in exactly the same manner as the statements:
k = k + (k = 4) * (k + 2); a[0] = a[0] + (a[0] = 4) * (a[0] + 2);