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:
- Comparisons such as
>=,==and<are evaluated first. !applies to the value right after it.&&comes next.||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 <= 30does 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 <= 30is 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.
- Write the age check. It has two parts joined by
&&:age >= 18andage <= 30. Put it in parentheses. - Add the flag. Put
specialStudenton the left of||, with the parenthesised age check on the right. The flag is already aBoolean, so it needs no comparison. Only one side of an||has to be true. - Print inside the
if:println("Let him in!"). - Add the
elseas} 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
| specialStudent | age | Output |
|---|---|---|
false | 18 | Let him in! |
false | 30 | Let him in! |
false | 17 | Not allowed |
false | 31 | Not allowed |
true | 50 | Let 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.