Start learning free

LESSON 79 OF 348 · CONDITIONAL STATEMENTS

Combining Logical Operators in Kotlin: &&, || and !

Lesson Read the full explanation

Sometimes we need to combine logical operators to evaluate more complex conditions. For example:

7 >= 10 && (5 == 7 || 9 < 12) // Evaluates to false

Notice that we used parentheses to group 5 == 7 and 9 < 12 together. The computer interprets this line of code as condition1 && condition2 where:

  • condition1 is 7 >= 10, which is false
  • condition2 is (5 == 7 || 9 < 12), which is true
At least one of condition1 and condition2 is false, so the entire condition is false.

It is very important to use parentheses to tell the computer how to group the conditions together. If we change the parentheses in the example above to:

(7 >= 10 && 5 == 7) || 9 < 12 // Evaluates to true

Now the computer interprets this line of code as condition1 || condition2 where:

  • condition1 is (7 >= 10 && 5 == 7), which is false
  • condition2 is 9 < 12, which is true
At least one of condition1 and condition2 is true, so the entire condition is true.

Assignment
Follow the Coding Tutorial and let's combine some logical operators.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 2
    Ctrl + Enter to check

    KOTLIN · CONDITIONAL STATEMENTS

    Combining Logical Operators in Kotlin, explained

    Why combine operators

    Real conditions are rarely a single comparison. "Let the student in if they are a special student, or if their age is between 18 and 30" needs a comparison for each end of the age range, plus a Boolean flag, joined in the right way. Kotlin gives you three logical operators for this: && (and), || (or) and ! (not). You can mix them in one condition.

    Precedence: which operator goes first

    When several operators appear together, Kotlin does not simply read left to right. The order is:

    1. Comparisons such as >=, == and < are evaluated first.
    2. ! applies to the value right after it.
    3. && comes next.
    4. || comes last.

    So && binds tighter than ||, in the same way that * binds tighter than +. The expression a || b && c means a || (b && c).

    Parentheses decide the grouping

    Parentheses override the default order, and they are worth adding even when they change nothing, because they tell the reader what you meant. Take the same three comparisons grouped two ways:

    println(7 >= 10 && (5 == 7 || 9 < 12))   // false
    println((7 >= 10 && 5 == 7) || 9 < 12)   // true
    

    In the first line, the parentheses group 5 == 7 and 9 < 12 with ||. That group is true, but the left side of the &&, 7 >= 10, is false, so the whole expression is false. In the second line, the group is 7 >= 10 && 5 == 7, which is false, and || then combines it with 9 < 12, which is true. The same comparisons give opposite answers.

    The default order gives a third reading of the same comparisons. Without any parentheses, 7 >= 10 && 5 == 7 || 9 < 12 is read as the second line and gives true. Don't rely on that: write the parentheses.

    Short-circuiting

    Kotlin stops evaluating as soon as the answer is known. In a && b, if a is false, then b is skipped. In a || b, if a is true, then b is skipped. This is useful for guarding a risky check behind a safe one, for example name != null && name.length > 3, where the length is only read after the null check passes.

    Common mistakes

    • Chaining comparisons like in maths. 18 <= age <= 30 does not compile in Kotlin. Write two comparisons joined by &&: age >= 18 && age <= 30. A range check, age in 18..30, is a neat alternative.
    • Using || where you need &&. age >= 18 || age <= 30 is true for every number, because any age is at least 18 or at most 30. A range needs both bounds to hold at once.
    • Relying on precedence you can't see. A condition that works only because && comes before || is easy to misread and easy to break when someone edits it.
    • Off-by-one bounds. "Between 18 and 30" in this lesson includes both ends, so use >= and <=. With > and <, ages 18 and 30 would be wrongly rejected.

    The lesson's exercise

    The code declares val specialStudent: Boolean = false and val age: Int = 23. A student is let in if specialStudent is true or age is between 18 and 30, both ends included. Anyone else is turned away.

    1. Write the age check. It has two parts joined by &&: age >= 18 and age <= 30. Put it in parentheses.
    2. Add the flag. Put specialStudent on the left of ||, with the parenthesised age check on the right. The flag is already a Boolean, so it needs no comparison. Only one side of an || has to be true.
    3. Print inside the if: println("Let him in!").
    4. Add the else as } else {, printing "Not allowed". It runs when both the flag and the age check fail.
    val specialStudent: Boolean = false
    val age: Int = 23
    
    if (specialStudent || (age >= 18 && age <= 30)) {
        println("Let him in!")
    } else {
        println("Not allowed")
    }
    

    Here specialStudent is false, but age >= 18 and age <= 30 are both true for 23, so the group is true and the program prints Let him in!.

    Trying other values

    specialStudentageOutput
    false18Let him in!
    false30Let him in!
    false17Not allowed
    false31Not allowed
    true50Let him in!

    The last row shows the point of ||: a special student gets in whatever their age is.

    Key takeaways

    • You can mix &&, || and ! in one condition. && is evaluated before ||.
    • Parentheses change the grouping and make it visible. Use them whenever && and || appear together.
    • A range test needs both bounds joined by &&, with >= and <= when the ends are included.
    • Evaluation stops as soon as the result is known.
    Keep going with KotlinAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free