JavaRush /Courses /Kotlin SELF /Operator precedence and parentheses in conditions

Operator precedence and parentheses in conditions

Kotlin SELF
Level 3, Lesson 4
Available

1. Introduction

Let’s start with an everyday analogy. Imagine a recipe:

Mix flour, eggs, and sugar, whisk, add butter, whisk again.

Looks weird? Now imagine that between the words “whisk” and “add” there is a comma or parentheses. The order of actions immediately becomes clearer.

In programming, a similar situation happens when you write a complex expression:

val result = a > 0 && b < 10 || c == 3

What’s the order? What is evaluated first: a > 0 && b < 10, then || c == 3? Or the other way around?
Without a clear evaluation order, the computer can “mix up the ingredients,” and your result will be unexpected.

2. Operator precedence in Kotlin

Kotlin (like most programming languages) uses a defined operator precedence table.
Operators with higher precedence are evaluated before operators with lower precedence.

Take a look at the most important part of this table (for conditional expressions):

Operator Description Precedence
()
Parentheses highest
!
Logical “NOT” high
==, !=
Equal / not equal medium
<, >, <=, >=
Comparisons medium
&&
Logical “AND” lower
||
Logical “OR” even lower

(There are also arithmetic operators—they have higher precedence than logical ones.)

Main rule

“AND” operators (&&) have higher precedence than “OR” (||),
meaning “AND” is evaluated first, then “OR”. It’s not a coincidence: AND is like logical multiplication, and OR is like addition.

Flowchart of condition precedence evaluation

graph LR
    A["a > 0"] --&&--> B["b < 10"]
    B --||--> C["c == 3"]

In practice: a > 0 && b < 10 || c == 3 — first it evaluates a > 0 && b < 10, then it combines that result with c == 3 using ||.

3. Operator direction: left-to-right and the opposite

Besides precedence, there’s another concept: associativity. This rule defines in which direction operators are evaluated when they appear “next to each other” and have the same precedence.

Example:

val a = true
val b = false
val c = true

val result = a && b && c

Question: how will it be evaluated?
Answer: the associativity of && is left-to-right.
So first a && b, then the result with c.

For conditions:

Operator Associativity
&&, ||
left-to-right
!
right-to-left

4. Parentheses are your best friend in complex conditions

This is where the magic (and the rescue) begins. When you write an expression, parentheses change the precedence and make your code clearer and safer.

Example 1 (without parentheses):

val isAdult = age >= 18
val isCitizen = country == "Belarus"
val hasPermit = hasSpecialPass == true

if (isAdult && isCitizen || hasPermit){
    println("Access granted!")
}

How Kotlin evaluates it:
First it evaluates isAdult && isCitizen, then it combines the result via || with hasPermit.

  • Suppose isAdult = true, isCitizen = false, hasPermit = true
  • isAdult && isCitizen → true && false → false
  • false || true → true

That is, if a person has a special pass, they will be let in anyway.
And if they don’t have a special pass, but they are an adult citizen—they will also be let in.

Example 2 (with parentheses):

if (isAdult && (isCitizen || hasPermit)) {
    println("Access granted!")
}

Now the program checks first:
isCitizen || hasPermit, and then that result together with isAdult.

Meaning you need to be an adult and (either a citizen or have a special pass).
A small difference in parentheses—a huge difference in logic!

5. Arithmetic and comparisons in one condition

A separate category of bugs is when calculations and comparisons are mixed within a single condition. Kotlin will figure it out, but a person can easily read it the wrong way.

For example:

fun main() {
    val x = 3
    val y = 4
    val limit = 10

    val exceeds = x + y > limit
    println(exceeds) // false
}

This reads fine because we have a simple template: “the sum is greater than the limit”. But imagine the expression becomes more complex:

fun main() {
    val x = 3
    val y = 4
    val z = 5
    val limit = 10

    val ok = x + y * z > limit
    println(ok) // true
}

Here Kotlin first does y * z, then adds x, then compares. If what you wanted was “first add x + y, then multiply by z”, then without parentheses you’ll get the wrong logic. The fix looks boring, but it’s honest:

fun main() {
    val x = 3
    val y = 4
    val z = 5
    val limit = 10

    val ok = (x + y) * z > limit
    println(ok) // true
}

Yes, here it’s also true, but now at least it’s clear why. And if you change the numbers, the difference will quickly become noticeable—and these “barely noticeable” bugs are exactly what end up costing time later.

1
Task
Kotlin SELF, level 3, lesson 4
Locked
The Magic of Parentheses
The Magic of Parentheses
1
Task
Kotlin SELF, level 3, lesson 4
Locked
Logical Shield
Logical Shield
1
Task
Kotlin SELF, level 3, lesson 4
Locked
Ads and restrictions
Ads and restrictions
1
Task
Kotlin SELF, level 3, lesson 4
Locked
Alert threshold
Alert threshold
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION