انتقل إلى المحتوى
أمين أبوزيد
منشورBEG-010-L04

الزيادة والنقصان والأسبقية

  • الدرس 4 من 6
  • 13 دقيقة قراءة
  • مبتدئ
في هذا الدرس 11 موضوعات

هذا الدرس متاح حاليًا باللغة الإنجليزية فقط، ولم تُنشر نسخته العربية بعد.

Lesson Overview

This lesson has two parts that belong together. The first is a pair of tiny operators, ++ and --, that add or subtract one. The second is precedence: the rules that decide which part of a long expression is calculated first. Both are about the same question, "in what order does Java do things?", and getting that order wrong is the source of many wrong answers that look right.

On the calculator from the previous lessons, ++ is a "+1" button. The twist is that you can press it before or after the variable, and the two give different results when used inside a bigger expression. Precedence is the calculator's built-in order of operations: multiplication before addition, as you learned in school, extended to every operator in Java.

Why this matters: counters, ids, and indexes are incremented all the time, and conditions mix arithmetic, comparisons, and logic. If you cannot predict the answer on paper, you cannot find the bug when the program disagrees with you.

This lesson builds on Lessons 1 to 3: arithmetic, comparison and logical operators, and assignment.

Learning Objectives

By the end of this lesson you will be able to:

  • Use ++ and -- as stand-alone statements to add or subtract one.
  • Explain the difference between prefix (++i) and postfix (i++) when the result is used.
  • Predict the values of variables after expressions that mix ++ or -- with other operators.
  • Use the precedence order of the operators from this module to evaluate mixed expressions by hand.
  • Explain left-to-right grouping for operators of equal precedence, and its effect on 7 / 2 * 2.0.
  • Use parentheses to make the intended order obvious.

Written Explanation

The increment and decrement operators

i++ adds 1 to i, and i-- subtracts 1. They are shorthand for i += 1 and i -= 1. As their own statement, i++; and ++i; do exactly the same thing:

java
int n = 3;
n++;
++n;
// n is now 5

The operand must be a variable. 5++ is not valid, because there is no box to store the new value in.

Prefix and postfix

Both forms change the variable by one. They differ in the value of the expression itself, which you only see when you use that value:

FormNameWhat the expression givesVariable afterwards
i++postfixthe old value, before the changeold value + 1
++iprefixthe new value, after the changeold value + 1
i--postfixthe old valueold value - 1
--iprefixthe new valueold value - 1

The Java Language Specification says the same thing for each form: postfix returns the value from before the update, and prefix returns the value after it. One way to remember: the symbol's position tells you when the change happens relative to the use. In i++ the variable is used, then it increments. In ++i it increments, then it is used.

java
int i = 5;
int a = i++;   // a gets 5, then i becomes 6
int b = ++i;   // i becomes 7, then b gets 7

Why you should limit them

An increment that is used inside a larger expression is allowed, but it is hard to read. Consider:

java
int k = 1;
int r = k++ * 10 + k;

Java evaluates operands from left to right (JLS section 15.7). First k++ gives 1 and k becomes 2. Then 1 * 10 is 10, and the second k is read as 2, so r is 12. The answer depends on the order of reading, which is exactly what readers misjudge.

A worse trap: m = m++; leaves m unchanged. The right side gives the old value, the increment happens, and then the assignment stores the old value back over it. Good style: use ++ and -- as separate statements, and use the value of the expression only in simple cases such as int id = next++;.

Precedence: which operator goes first

Precedence is the rule for which operator is applied first when an expression has several. It is the same idea as "multiplication before addition". The Java Tutorials list the operators from highest to lowest precedence. Here is the part you need for this module:

Level (highest first)Operators
postfixi++ i--
unary++i --i +x -x !
multiplicative* / %
additive+ -
relational< > <= >=
equality== !=
logical AND&&
logical OR||
assignment= += -= *= /= %=

Operators on the same row have equal precedence. Operators on a higher row bind more tightly. That is why:

  • 2 + 3 * 4 is 14, because * is applied before +.
  • 10 - 2 * 3 > 3 + 0 first does the arithmetic (4 > 3), then the comparison, giving true.
  • 5 > 3 && 2 + 2 == 4 || false does the arithmetic, then the comparisons, then &&, then ||.
  • Assignment is last, so x = 2 + 3 computes the sum before storing.

This table is why Lessons 1 to 3 worked: n % 2 == 0 applies % first, then ==, and cartItems > 0 && !suspended applies the comparison and the ! before the &&.

Equal precedence: left to right

When two operators from the same row appear next to each other, Java groups them from the left (assignment is the exception: it groups from the right, as you saw with a = b = 7).

  • 20 - 5 - 3 is (20 - 5) - 3, which is 12. It is not 20 - (5 - 3), which is 18.
  • 7 / 2 * 2.0 is (7 / 2) * 2.0. The 7 / 2 is integer division and gives 3, so the result is 6.0. Compare 7 / (2 * 2.0), which is 1.75.
  • 2 + 3 * 4 % 5: * and % are on the same row, so 3 * 4 is 12, then 12 % 5 is 2, then 2 + 2 is 4.

The second example is a trap worth remembering: the type of each division is decided by its own two operands, so an early int / int can drop the fraction even if a double appears later in the expression.

Parentheses

Parentheses override precedence. They are evaluated first, innermost first. You do not have to memorize the whole table. A good rule is: know the big ordering (arithmetic, then comparison, then &&, then ||), and add parentheses whenever a reader could hesitate. (a && b) || c has the same meaning as a && b || c, and it is much safer to read.

Examples

Example 1: prefix versus postfix (simple)

java
public class Inc {
    public static void main(String[] args) {
        int i = 5;
        int a = i++;
        System.out.println("a=" + a + " i=" + i);
        int b = ++i;
        System.out.println("b=" + b + " i=" + i);
        int c = i--;
        System.out.println("c=" + c + " i=" + i);
        int d = --i;
        System.out.println("d=" + d + " i=" + i);
        int k = 1;
        int r = k++ * 10 + k;
        System.out.println("r=" + r + " k=" + k);
        int m = 3;
        m = m++;
        System.out.println("m=" + m);
        int n = 3;
        n++;
        ++n;
        System.out.println("n=" + n);
    }
}

Output (JDK 21):

text
a=5 i=6
b=7 i=7
c=7 i=6
d=5 i=5
r=12 k=2
m=3
n=5

Line 1: postfix gave the old 5. Line 2: prefix gave the new 7. Lines 3 and 4 repeat the pattern with --. Line 5 is the k++ * 10 + k example from above, line 6 is the unchanged m, and line 7 shows that stand-alone n++ and ++n act the same.

Example 2: precedence on paper, then in code (practical)

java
public class Prec {
    public static void main(String[] args) {
        System.out.println(2 + 3 * 4);
        System.out.println((2 + 3) * 4);
        System.out.println(20 - 5 - 3);
        System.out.println(20 - (5 - 3));
        System.out.println(7 / 2 * 2.0);
        System.out.println(7 / (2 * 2.0));
        System.out.println(2 + 3 * 4 % 5);
        System.out.println(10 - 2 * 3 > 3 + 0);
        int x = 4;
        System.out.println(-x * 2);
        System.out.println(1 + 2 < 4 == true);
        System.out.println(5 > 3 && 2 + 2 == 4 || false);
    }
}
text
14
20
12
18
6.0
1.75
4
true
-8
true
true

Each pair of neighbours (lines 1 and 2, 3 and 4, 5 and 6) differs only by parentheses. Line 10 reads ((1 + 2) < 4) == true: the arithmetic first, then < (relational, higher), then ==.

Example 3: ids, stock, and a discount (realistic)

java
public class Ticket {
    public static void main(String[] args) {
        int nextId = 100;
        int first = nextId++;
        int second = nextId++;
        int third = ++nextId;
        System.out.println(first + " " + second + " " + third + " next=" + nextId);
        int stock = 3;
        stock--;
        stock--;
        System.out.println("stock=" + stock);
        int price = 1000;
        int qty = 3;
        int discountPercent = 10;
        int total = price * qty - price * qty * discountPercent / 100;
        System.out.println(total);
        boolean ok = total > 2000 && qty >= 3 || stock == 0;
        System.out.println(ok);
    }
}
text
100 101 103 next=103
stock=1
2700
true

The first line: first takes 100, second takes 101, and third takes 103, because the prefix form increments to 103 before it is used, skipping 102. This is a classic id-skipping bug, and it comes from choosing prefix when postfix was meant. total is 3000 - 300, since the multiplications and division happen before the subtraction.

Backend Insight

Counters and ids appear everywhere in backend code: request counts, retry attempts, array positions, sequence numbers. count++ as a stand-alone line is by far the most common form, and that is the form to prefer. When an id is generated, the choice between "use the old value, then advance" and "advance, then use" decides whether ids start at 100 or 101, or skip a number. In real systems ids usually come from the database, which is safer than a counter in memory, but the thinking is the same.

Precedence matters in the conditions that guard business rules, such as isAdmin || isOwner && !locked. The meaning of that line, and who can access what, depends entirely on the grouping. In reviews and in security-sensitive code, parentheses are cheap insurance. Later chapters on debugging and test boundaries rely on your ability to evaluate an expression step by step, exactly as this lesson trains.

Common Mistakes

Mistake 1: Confusing prefix and postfix

  • Incorrect: expecting int b = i++; to give the new value.
  • Correct: postfix i++ gives the old value; use ++i when you want the new one.

Mistake 2: i = i++

The variable ends up with its old value. Write i++; on its own line instead.

Mistake 3: Early integer division

7 / 2 * 2.0 is 6.0, not 7.0. The first division uses two ints. If you want decimals, start with one: 7 / 2.0 * 2.

Mistake 4: Grouping subtraction wrongly

20 - 5 - 3 is 12, because equal-precedence operators group from the left.

Mistake 5: Relying on precedence you cannot recite

If you need to look up the order, so will the next reader. Add parentheses.

Mistake 6: Using several increments of one variable in one expression

An expression such as i++ + ++i is legal but nobody should have to decode it. Split it into separate statements.

Exercises

Try each exercise yourself before opening the solutions. Write your prediction first.

Level A: Foundation

A1. Evaluate: 3 + 4 * 2, (3 + 4) * 2, 12 / 3 / 2, 12 / (3 / 2).

أظهر الحل A1

A1. 11, 14, 2 ((12 / 3) / 2), and 12 (3 / 2 is 1 in integer division, so 12 / 1).

A2. After int i = 10; i++; i--; i--;, what is i?

أظهر الحل A2

A2. 9. Starting at 10, i++ makes 11, the first i-- makes 10, and the second i-- makes 9.

A3. After int i = 4; int j = i--;, what are i and j?

أظهر الحل A3

A3. j gets the old value 4, then i becomes 3. So i is 3 and j is 4.

Level B: Application

B1. Predict p and q: int p = 5; int q = ++p * 2;

أظهر الحل B1

B1. ++p makes p 6 and gives 6, then 6 * 2 is 12. So p is 6 and q is 12.

B2. Evaluate by hand, showing the order of steps: 1 + 2 * 3 - 4 / 2 + 5 % 3.

أظهر الحل B2

B2. 2 * 3 is 6; 4 / 2 is 2; 5 % 3 is 2. The expression becomes 1 + 6 - 2 + 2, which is evaluated from the left: 7, then 5, then 7. The answer is 7.

B3. Evaluate: 2 + 3 > 4 && 10 % 3 == 1 || false. Which operator is applied last?

أظهر الحل B3

B3. 2 + 3 > 4 is 5 > 4, which is true. 10 % 3 == 1 is 1 == 1, which is true. Then true && true is true, and true || false is true. The || is applied last; the answer is true.

Level C: Challenge

C1. int a = 3; int b = a++ * 2 + a; then int c = ++a * 2 + a; Give a, b, and c at the end.

أظهر الحل C1

C1. b = a++ * 2 + a: a++ gives 3 and a becomes 4, 3 * 2 is 6, plus the current a (4) gives b = 10. Then ++a makes a 5 and gives 5, 5 * 2 is 10, plus a (5) gives c = 15. Final values: a = 5, b = 10, c = 15.

C2. A formula for the average of three ints x, y, z is written x + y + z / 3.0. Explain what it really computes, using x = 3, y = 6, z = 9, and fix it.

أظهر الحل C2

C2. Division binds tighter than addition, so it computes x + y + (z / 3.0), which is 3 + 6 + 3.0 = 12.0, not the average (6.0). Fix: (x + y + z) / 3.0, which gives 6.0.

Mini Challenge

Write a program Steps with an int level = 1; and print a line after each step:

  1. A stand-alone level++;.
  2. int shown = level++; and print both shown and level.
  3. int next = ++level * 2; and print next and level.
  4. Print the value of 1 + level * 2 > 10 && level % 2 == 1 (predict with the table first).

Check your work: write your predictions on paper before you run the program. After step 1 the level is 2; after step 2 shown is 2 and level is 3; after step 3 next is 8 and level is 4, and the last expression is false.

Summary & Next Lesson

Key takeaways

  • ++ and -- add or subtract one. As a stand-alone statement the prefix and postfix forms are identical.
  • In an expression, postfix (i++) gives the old value and prefix (++i) gives the new one. Both change the variable by one.
  • Precedence, high to low: postfix and unary, then * / %, then + -, then comparisons, then &&, then ||, then assignment.
  • Equal precedence groups from the left, so 20 - 5 - 3 is 12 and 7 / 2 * 2.0 is 6.0.
  • Parentheses make the order explicit; use them whenever a reader could hesitate.

Next lesson

Next is "Short-circuit evaluation": how && and || sometimes skip their right side entirely, and how to use that to write conditions that can never crash.

Self-check

  1. After int i = 1; int j = i++;, what are i and j?
  2. After int i = 1; int j = ++i;, what are i and j?
  3. What is 8 - 3 * 2?
  4. What is 100 / 10 / 5?
  5. What do you do when you are not sure how an expression will be grouped?
أظهر الإجابات
  1. i is 2 and j is 1.
  2. i is 2 and j is 2.
  3. 2: the multiplication gives 6 first, and 8 - 6 is 2.
  4. 2. It is (100 / 10) / 5, which is 10 / 5.
  5. Add parentheses so the order is explicit, and check the result with a small test.

References

  • Oracle, The Java Tutorials: Operators. It provides the operator precedence table used above and the rule that binary operators other than assignment are evaluated left to right.
  • Oracle, The Java Language Specification, Java SE 21, Chapter 15: Expressions. Sections 15.14.2 and 15.15.1 say that postfix increment gives the value before the update and prefix increment gives the value after it. Section 15.7 says operands are evaluated left to right.
  • All outputs above came from compiling and running the code with JDK 21.

التطبيق

طبّق هذا الدرس بمختبر الوحدة وتمارينها واختبارها.

المختبر والتمارين الاختبار

تعليم الدرس كمكتمل اختياري ويمكنك التراجع عنه في أي وقت. يبقى تقدمك محفوظًا في هذا المتصفح.

اكتب للبحث في المستويات والمراحل والوحدات والدروس.