Classes/Objects  «Prev  Next»


Lesson 8 Determining order of evaluation
ObjectiveDescribe how operator precedence and associativity is used.

Java Operator Precedence and Associativity in Java SE 21

In Java, 1) operator precedence and 2) associativity determine the order in which operators are evaluated in expressions. Understanding these concepts is essential for writing correct and efficient code.
1) Operator Precedence: Operator precedence defines the order in which different operators are evaluated in an expression. Operators with higher precedence are evaluated before operators with lower precedence.
Operator Precedence Table Below is a comprehensive list of Java operators ordered from highest to lowest precedence:
  1. Postfix: expr++, expr--
  2. Unary: ++expr, --expr, +expr, -expr, ~, !
  3. Creation or Casting: new, (type)
  4. Multiplicative: *, /, %
  5. Additive: +, -
  6. Shift: <<, >>, >>>
  7. Relational: <, >, <=, >=, instanceof, pattern instanceof (since Java 16)
  8. Equality: ==, !=
  9. Bitwise AND: &
  10. Bitwise XOR: ^
  11. Bitwise OR: |
  12. Logical AND: &&
  13. Logical OR: ||
  14. Ternary Conditional: ?:
  15. Assignment: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, >>>=


Examples of Different Types of Java Operators

  • Multiplicative vs. Additive Operators
    int result = 2 + 3 * 4;
    

    Evaluation:
    1. Multiplication (*) has higher precedence than addition (+).
    2. Calculate 3 * 4 → 12.
    3. Then add 2 + 12 → 14.

    Result: result is 14.
  • Unary vs. Postfix Operators
    int a = 5;
    int b = a++;
    int c = ++a;
    

    Evaluation:
    1. b = a++; assigns 5 to b, then increments a to 6.
    2. c = ++a; increments a to 7, then assigns 7 to c.

    2) Associativity
    Associativity determines the order in which operators of the same precedence level are evaluated. It can be left-to-right (left-associative) or right-to-left (right-associative).
  • Left-Associative Operators
    Most binary operators are left-associative.
    Example:
    int result = 100 / 10 / 2;
    

    Evaluation:
    1. (100 / 10) → 10.
    2. (10 / 2) → 5.

    Result: result is 5.
  • Right-Associative Operators
    Assignment operators and the ternary conditional operator are right-associative.
    Example:
    int x, y, z;
    x = y = z = 10;
    

    Evaluation:
    1. z = 10;
    2. y = z;
    3. x = y;

    Result: All variables x, y, and z have the value 10.
  • Non-Associative Operators: Some operators are non-associative and cannot be chained without parentheses.
    Example:
    boolean result = true ? false : true ? false : true;
    

    Evaluation:
    • The ternary operator ?: is right-associative.
    • Evaluates as true ? false : (true ? false : true);


Special Considerations in Java SE 21

Java SE 21 continues to use the same operator precedence and associativity rules as previous versions. However, it introduces enhancements like pattern matching for switch expressions and record patterns, which can affect how expressions are evaluated.
Pattern Matching for switch:
switch (obj) {
    case String s -> System.out.println("It's a string: " + s);
    case Integer i -> System.out.println("It's an integer: " + i);
    default -> System.out.println("Unknown type");
}

Note: The instanceof operator now supports pattern matching, but this does not change its precedence or associativity.
Tips for Using Operator Precedence and Associativity
  1. Use Parentheses for Clarity: When in doubt, use parentheses to make the order of evaluation explicit.
    int result = 2 + (3 * 4); // Clear and unambiguous
    
  2. Be Mindful of Side Effects: Operators like ++ and -- can have side effects that affect the outcome.
    int i = 0;
    int array[] = {0, 1, 2, 3};
    array[i++] = i;
    // Be cautious with such expressions
    
  3. Understand Short-Circuit Evaluation: Logical operators && and || short-circuit, meaning they don't evaluate the right-hand side if not necessary.
    if (obj != null && obj.isValid()) {
      // Safe to use obj
    }
    
  4. Avoid Complex Expressions: Break down complex expressions into multiple statements for better readability and maintainability.

Common Pitfalls
Mixing Bitwise and Logical Operators:
Remember that & and | are bitwise operators, while && and || are logical operators.
// Bitwise AND
int flags = flag1 & flag2;

// Logical AND
if (condition1 && condition2) { ... }

Assignment in Conditional Statements:
if (x = y) { ... } // Error: assignment instead of comparison

// Correct way
if (x == y) { ... }

The assignment operator = has lower precedence than the equality operator ==, but accidental use can lead to logical errors.
Summary
  • Operator Precedence: Determines the order in which different operators are evaluated.
  • Associativity: Determines the order in which operators of the same precedence level are evaluated.
    • Left-associative: Evaluated from left to right.
    • Right-associative: Evaluated from right to left.
    • Non-associative: Cannot be chained without explicit grouping.
  • Java SE 21: No changes to operator precedence or associativity, but new language features like pattern matching may affect code structure.

By understanding and applying these rules, you can write clearer and more predictable Java code. Always refer to the official Java documentation for the most accurate and detailed information.

Modern Java

Order of Evaluation for Operators

Describe how operator precedence and associativity is used to determine the order in which expressions are evaluated.
The order of evaluation of Java expressions is dependent on the precedence and associativity of the operators used in the expression, and the use of parentheses. In general, the operands of expressions are evaluated in a left-to-right order before any operations are performed. The exceptions to this are expressions involving the &&, ||, and ternary operators. Once an expression's operands are evaluated, the operators are applied according to operator precedence and associativity. The assignment operator is the only right-associative binary operator. Parentheses can be used to change the ordering imposed by precedence and associativity. The following table shows the precedence of Java's operators. Higher-level operators take precedence over lower-level operators. Operators at the same level are evaluated based on the order they appear and their associativity.
  1. Order of evaluation: The order in which expressions are evaluated.
  2. Precedence: The order in which operations are performed.

Modern Java
Operator precedence table
Here is the transcribed **operator precedence chart** from the image you provided (from **high to low precedence**): --- 🔝 Top (High Precedence)
  1. ++ (postfix), -- (postfix)
  2. ++ (prefix), -- (prefix), + (unary), - (unary), ~, !
  3. (type)
  4. *, /, %
  5. + (binary), - (binary)
  6. <<, >>, >>>
  7. <, >, <=, >=
  8. ==, !=
  9. &
  10. ^
  11. &&
  12. ||
  13. ?: (ternary conditional operator)

🔚 Bottom (Low Precedence)
  1. `=`, `+=`, `-=`, `*=`, `/=`, `%=`, `<<=`, `>>=`, `>>>=`, `&=`, `^=`, `|=`

Java already has a rule in place for just such a situation. Table 4.8 lists the precedence of operators: the operator on top has the highest precedence, and operators within the same group have the same precedence and are evaluated from left to right.
Table 4.8  Precedence of operators
Table 4.8 Precedence of operators

Let us execute an expression that uses multiple operators (with different precedence) in an expression:
int int1 = 10, int2 = 20, int3 = 30;
System.out.println(int1 % int2 * int3 + int1 / int2);

Prints 300
Because this expression defines multiple operators with different precedence, it is evaluated as follows:
(((int1 % int2) * int3)) + (int1 / int2)
(((10 % 20) * 30)) + (10 / 20)
( (10 * 30)) + (0)
( 300 )

Java Operator Precedence

The Precedence program

The Precedence program provides an example of how complex expressions are evaluated and provides an example of how to use precedence and associativity to evaluate a complex expression.
The result displayed by the program is 107.
At first glance, the following expression may seem daunting.
s = s += i = b ? 1 + 2 * i++ : --i;

However, if you evaluate it step by step, you will be able to quickly and methodically arrive at the correct result. The first thing that you should note is that the ternary operator is used. The ternary operator is a short-circuit operator, which means that its second and third operands will only be (conditionally) evaluated based on the result of the first operand. Since the ternary operator has higher precedence than the = and += operators, it is evaluated first.
Since b is true, the result returned by the ternary operator is 1 + 2 * i++. The ++ operator has a higher precedence than *, which has a higher precedence than +. The result returned by the ternary operator is 1 + (2 * (i++)), which is 1 + (2 * 3) or 7.
Substituting 7 in the overall expression, we now have:
					
s = s += i = 7;

The = and += operators have the same precedence, but they are right-associative. The expression is evaluated as:
					
s = (s += (i = 7));

which results in 7 being assigned to i, and appended to s. Since the value of s is "10" before the expression is evaluated, its final value is "107".
  • Precedence
    public class Precedence {
    
      public static void main(String[] args) {
        String s = "10";
        int i = 3;
        boolean b = true;
        s = s += i = b ? 1 + 2 * i++ : --i;    
        System.out.println(s);
      }
    }
    


SEMrush Software