Updating a variable from its own value
Programs constantly update a variable using what it already holds: add a score to a running total, halve a size, count one more event. By Topic 1.4 you can write this as
int total = 20;
total = total + 5;
Java offers a shorter form that says the same thing. A compound assignment operator performs an arithmetic operation between the value on the left and the value on the right, and then assigns the result to the variable on the left.
| Compound form | Meaning | Ordinary form |
|---|---|---|
x += e |
add | x = x + (e) |
x -= e |
subtract | x = x - (e) |
x *= e |
multiply | x = x * (e) |
x /= e |
divide | x = x / (e) |
x %= e |
remainder | x = x % (e) |
The brackets around e matter. The right side is worked out in full first, and only then combined with x. So with int x = 4;, the statement x *= 2 + 3; means x = x * (2 + 3), which is 20, not (4 * 2) + 3, which is 11.
Adding and subtracting 1
Adding or subtracting 1 is so common that it has its own operators. The post-increment operator ++ adds 1 to the stored value of a numeric variable and assigns the new value to the variable. The post-decrement operator -- subtracts 1. As separate statements:
int count = 3;
count++; // same as count += 1; and count = count + 1; (count is now 4)
count--; // same as count -= 1; and count = count - 1; (count is back to 3)
In this course the operators are written after the variable and used as statements on their own. Prefix forms such as ++x, and uses inside other expressions such as arr[x++], are outside the scope of the course and exam.
Tracing a sequence
Follow score through a sequence of updates. Each statement uses the value left by the one before.
public class Compound {
public static void main(String[] args) {
int score = 10;
score += 5;
score -= 3;
score *= 2;
score /= 5;
score %= 3;
score++;
score--;
score--;
System.out.println(score);
}
}
0
The type of the variable controls the arithmetic. score is an int, so score /= 5 is integer division: 24 / 5 is 4, with the 0.8 thrown away, and score %= 3 is the remainder 4 % 3 = 1. If score had been a double, score /= 5 would have given 4.8.
public class Types {
public static void main(String[] args) {
double price = 20.0;
price /= 8;
System.out.println(price);
price -= 0.5;
System.out.println(price);
int items = 20;
items /= 8;
System.out.println(items);
}
}
2.5
2.0
2
A detail to notice: the result goes back into the variable’s type
When the variable on the left is an int and the right side is a double, Java converts the result back to an int for you, truncating the fraction (as a cast would in Topic 1.5). It does not report an error, so check the type of the variable on the left when you trace.
public class Back {
public static void main(String[] args) {
int n = 10;
n *= 1.5;
System.out.println(n);
int m = 5;
m *= 1.5;
System.out.println(m);
}
}
15
7
For m, the product 7.5 is truncated to 7 as it is stored. The plain assignment m = m * 1.5; would not compile, because it stores a double in an int.
Three jobs that compound assignment does all the time
Once you can read x op= e, you will see it do the same few jobs in almost every program. Recognising the job makes both writing and tracing faster.
Accumulating. Start a variable at a neutral value and keep adding to it: sum += price;. The variable collects a running total, and after each statement it holds the total so far. In Unit 2 the same statement will sit inside a loop; for now, each use is a single step in a sequence.
Counting. A counter goes up by one each time something happens: count++;. It starts at zero and, after each event, holds the number of events so far. A statement such as remaining--; counts down in the same way.
Scaling and reducing. Multiply to scale (price *= 2; doubles a price), divide to shrink or to share (pot /= 4;), and take the remainder to wrap a value into a fixed range (position %= 10; always leaves a number from 0 to 9 for a non-negative position). When a division is used to share whole items, remember that on an int it discards the leftover, and the remainder operator recovers it.
A useful habit when you meet a compound assignment is to read it aloud as a sentence: “price times-equals two” becomes “make price twice what it was”, and “total plus-equals tax” becomes “make total bigger by the tax”. If a statement will not read as a sentence in plain English, you have probably mis-parsed it, and the usual cause is not noticing how far the right side extends.
One more point about the order of statements. Because each statement uses the value left by the one before it, swapping two adjacent compound assignments usually changes the answer. Adding 5 and then doubling gives a different result from doubling and then adding 5: starting from 10, x += 5; x *= 2; leaves 30, but x *= 2; x += 5; leaves 25. Sequencing, which you met in Topic 1.1, is exactly what makes a trace table work.
Worked example 1: Trace a mixed sequence
Task. Trace the following code and state the final values of a, b and c.
int a = 17;
int b = 4;
double c = 2.5;
a %= b;
b *= a + 1;
c += b;
a++;
c /= 2;
Step 1, set up the table.
| After statement | a | b | c | Working |
|---|---|---|---|---|
int a = 17; |
17 | - | - | |
int b = 4; |
17 | 4 | - | |
double c = 2.5; |
17 | 4 | 2.5 | |
a %= b; |
1 | 4 | 2.5 | 17 % 4: 4 * 4 = 16, remainder 1 |
b *= a + 1; |
1 | 8 | 2.5 | the right side first: 1 + 1 = 2; then 4 * 2 = 8 |
c += b; |
1 | 8 | 10.5 | 2.5 + 8 (the int 8 is widened to 8.0) |
a++; |
2 | 8 | 10.5 | 1 + 1 |
c /= 2; |
2 | 8 | 5.25 | c is a double, so 10.5 / 2 is 5.25 |
Step 2, answer. The final values are a = 2, b = 8 and c = 5.25.
Step 3, the two traps in this example. First, b *= a + 1; uses a as it is after the previous statement (1), and the sum a + 1 is evaluated before the multiplication. Second, c /= 2; is a real division because c is a double. With an int it would have truncated.
Check by running.
public class Trace {
public static void main(String[] args) {
int a = 17;
int b = 4;
double c = 2.5;
a %= b;
b *= a + 1;
c += b;
a++;
c /= 2;
System.out.println(a + " " + b + " " + c);
}
}
2 8 5.25
Worked example 2: Split a bill
Task. Three items cost 250, 199 and 75 pence. The order is doubled, a coupon takes off 100 pence, and the total is shared equally between 4 people, using whole pence. Find what each person pays, in pounds and pence.
Step 1, plan in sequence. Keep the total in one int variable cents (using whole pence avoids the round-off error of Topic 1.5), and update it with compound operators in the order the story gives.
Step 2, work it out.
| Step | Statement | cents |
|---|---|---|
| Start | int cents = 0; |
0 |
| First item | cents += 250; |
250 |
| Second item | cents += 199; |
449 |
| Third item | cents += 75; |
524 |
| Doubled | cents *= 2; |
1048 |
| Coupon | cents -= 100; |
948 |
| Share between 4 | cents /= 4; |
237 |
Each share is 237 pence (948 / 4 is exactly 237).
Step 3, pounds and pence. Use / for whole pounds and % for the leftover pence, as in Topic 1.3. 237 / 100 is 2 and 237 % 100 is 37. With the compound form: int pence = cents; pence %= 100; gives 37.
public class Bill {
public static void main(String[] args) {
int cents = 0;
cents += 250;
cents += 199;
cents += 75;
cents *= 2;
cents -= 100;
cents /= 4;
int pounds = cents / 100;
int pence = cents;
pence %= 100;
System.out.println(pounds + " pounds " + pence + " pence");
}
}
2 pounds 37 pence
Step 4, check. Each person pays 2 pounds 37 pence. Four shares make 948 pence, which is the total after the coupon. (If the division had not been exact, /= would have dropped the remaining pence. That is a fact to keep in mind whenever you use integer division on money.)
Common misconceptions
- “
x *= 2 + 3meansx = x * 2 + 3.” The whole right side is evaluated first: it meansx = x * (2 + 3). - “
x =+ 5is the same asx += 5.”x =+ 5is an ordinary assignment of positive 5. It compiles, but it stores 5 inxand ignores the old value. The operator is+=with the plus first. - “
/=always keeps the fraction.” On anintvariable it is integer division. - “
x++returns the new value, so I can use it in an expression.” The course uses++and--only as separate statements. - “A compound assignment to an
intwith adoubleis an error.” It compiles, and the result is truncated when stored. - “
%=gives a percentage.” It stores the remainder. - “Each statement works on the original value of the variable.” Each uses the value left by the previous statement.
Where this leads
Practise with the Topic 1.6 practice questions, recap with the revision notes and tick off the checklist. The next topic, 1.7 Application Program Interface (API) and Libraries, moves from single variables to classes that other programmers have already written for you to use.
Quick questions
Is x += 5 exactly the same as x = x + 5?
For tracing values, yes: it adds 5 to the current value of x and stores the result in x. The shorthand is quicker to write and read. When the right side has several operators, treat it as bracketed: x *= 2 + 3 is x = x * (2 + 3).
What does x++ do?
The post-increment operator adds 1 to the stored value of a numeric variable and assigns the new value to the variable. As a statement on its own, x++; has the same effect as x += 1; and x = x + 1;.
Will the exam use ++x or arr[x++]?
No. Increment and decrement operators in prefix form (such as ++x) and inside other expressions (such as arr[x++]) are outside the scope of the course and exam. Use ++ and – as separate statements.
Can I use += with a double on the right and an int on the left?
It compiles, because Java converts the result back to the variable's type for you, truncating any fraction. For example int n = 3; n += 2.9; leaves n as 5. This is easy to miss when tracing, so check the type of the variable on the left.