JavaRush /Курси /Kotlin SELF /Пріоритет операторів і дужки в умовах

Пріоритет операторів і дужки в умовах

Kotlin SELF
Рівень 3 , Лекція 4
Відкрита

1. Вступ

Почнімо з побутової аналогії. Уявіть собі рецепт:

Змішайте борошно, яйця та цукор, збийте, додайте масло, збийте ще раз.

Виглядає дивно? А тепер уявіть, що між словами «збийте» і «додайте» стоїть кома або дужки. Порядок дій одразу стає зрозумілішим.

У програмуванні схожа ситуація виникає, коли ви пишете складний вираз:

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

Який тут порядок? Що обчислюється першим: a > 0 && b < 10, а потім || c == 3? Чи все навпаки?
Без чіткого порядку обчислень компʼютер може «переплутати інгредієнти» — і результат вийде несподіваним.

2. Пріоритет операторів у Kotlin

Kotlin (як і більшість мов програмування) має таблицю пріоритетів операторів.
Оператори з вищим пріоритетом виконуються раніше, ніж оператори з нижчим.

Подивіться на найважливішу частину цієї таблиці (для умовних виразів):

Оператор Опис Пріоритет
()
Дужки найвищий
!
Логічне «НЕ» високий
==, !=
Дорівнює / не дорівнює середній
<, >, <=, >=
Порівняння середній
&&
Логічне «І» нижче
||
Логічне «АБО» ще нижче

(Є ще арифметичні оператори — вони мають вищий пріоритет, ніж логічні.)

Головне правило

Оператори «І» (&&) мають вищий пріоритет, ніж «АБО» (||),
тобто спочатку буде обчислено «І», а потім «АБО». Недарма «І» — це логічне множення, а «АБО» — додавання.

Блок-схема обчислення пріоритету умов

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

На практиці вираз a > 0 && b < 10 || c == 3 обчислюється так: спочатку рахується a > 0 && b < 10, а потім результат поєднується з c == 3 через ||.

3. Напрямок обчислення: зліва праворуч і справа ліворуч

Окрім пріоритету, є ще одне поняття: асоціативність. Вона визначає, у якому напрямку виконуються оператори, якщо вони стоять поруч і мають однаковий пріоритет.

Приклад:

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

val result = a && b && c

Питання: як це обчислиться?
Відповідь: асоціативність у &&зліва праворуч.
Отже, спочатку a && b, а потім — результат разом із c.

Для умов:

Оператор Асоціативність
&&, ||
зліва праворуч
!
справа ліворуч

4. Дужки — ваш найкращий друг у складних умовах

Ось тут починається магія (і порятунок). Коли ви пишете вираз, дужки змінюють пріоритет і роблять код зрозумілішим та безпечнішим.

Приклад 1 (без дужок):

val isAdult = age >= 18
val isCitizen = country == "Україна"
val hasPermit = hasSpecialPass == true

if (isAdult && isCitizen || hasPermit){
    println("Доступ дозволено!")
}

Як обчислює Kotlin:
Спочатку обчислює isAdult && isCitizen, а потім поєднує результат через || із hasPermit.

  • Припустімо, isAdult = true, isCitizen = false, hasPermit = true
  • isAdult && isCitizentrue && falsefalse
  • false || truetrue

Тобто, якщо в людини є спецперепустка, її все одно пропустять.
А якщо спецперепустки немає, але це дорослий громадянин — теж пропустять.

Приклад 2 (із дужками):

if (isAdult && (isCitizen || hasPermit)) {
    println("Доступ дозволено!")
}

Тепер програма спочатку перевіряє:
isCitizen || hasPermit, а потім поєднує цей результат із isAdult.

Тобто вам потрібно бути дорослим і (або громадянином, або мати спецперепустку).
Невелика різниця в дужках — величезна різниця в логіці!

5. Арифметика та порівняння в одній умові

Окрема категорія помилок — коли в одній умові змішують обчислення та порівняння. Kotlin у цьому розбереться, а от людині легко прочитати вираз не так, як задумано.

Наприклад:

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

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

Це читається нормально, бо шаблон простий: «сума більша за ліміт». Але уявіть, що вираз ускладнюється:

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

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

Тут Kotlin спочатку множить y * z, потім додає x, а вже після цього порівнює результат. Якщо ви хотіли «спочатку скласти x + y, а потім помножити на z», то без дужок отримаєте іншу логіку. Виправлення виглядає нудно, зате чесно:

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

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

Так, тут теж true, але тепер принаймні зрозуміло, чому. А якщо змінити числа, різниця швидко стане помітною. Саме такі «ледь помітні» помилки потім і забирають час.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ