JavaRush /Курси /Java Syntax Zero /Особливості роботи різних операторів

Особливості роботи різних операторів

Java Syntax Zero
Рівень 9 , Лекція 7
Відкрита

1. Булеві операції

Оператори | і & можна застосовувати не тільки до чисел, а й до виразів зі значенням типу boolean.

Однак, як ви вже знаєте, для логічних виразів є оператори && і ||. Що ж нам дасть використання | замість || і використання & замість &&? Чи є взагалі в цьому сенс? Виявляється, є. Іноді.

Логічні оператори || і && виконуються зліва направо за принципом так званих лінивих обчислень.

(вираз1) || (вираз2) || (вираз3)

Якщо вираз1 дорівнює true, немає сенсу обчислювати вираз2 й вираз3: результат все одно буде true.

Тому під час обчислення виразів (а вони обчислюються один за одним зліва направо), щойно ми отримали true, обчислення решти виразів не виконується. І якщо вирази вираз2 й вираз3 містили виклики якихось функцій, то ці функції не викликаються!

Те саме відбувається й у випадку з логічним оператором &&:

(вираз1) && (вираз2) && (вираз3)

Якщо вираз1 дорівнює false, немає сенсу обчислювати вираз2 й вираз3: результат все одно буде false.

Це важливий момент, який дозволяє писати ось такі речі:

String s = null;
if (s != null && s.length() > 0) {

У прикладі вище ми ніколи не отримаємо NullPointerException, оскільки вираз s.length() виконуватиметься, тільки якщо перша частина, s != null, дорівнює true.

Якщо s виявиться рівним null, ліворуч від оператора && буде значення false, і результат усього логічного виразу буде false, тому обчислення другої частини (s.length() > 0) не виконується.

От до чого це все:

якщо в логічному виразі використати оператор | або оператор &, то лінивого обчислення не вийде — у всіх випадках буде обчислено всі вирази.



2. Пріоритет операцій у Java

Як ви, певно, пам'ятаєте зі шкільного курсу математики, операція множення має вищий пріоритет, ніж операція додавання. А дужки мають іще вищий пріоритет: спочатку обчислюються вирази в дужках, а потім уже виконуються множення/ділення й додавання/віднімання.

Оператори в Java теж мають пріоритет, тільки: а) їх дещо більше, б) деякі оператори виконуються зліва направо, а інші — справа наліво.

Отакий вигляд має таблиця з усіма операторами Java:

Категорія Оператор Асоціативність
Постфікс () [] . Зліва направо
Унарний ++ -- ! ~ Справа наліво
Мультиплікативний * / % Зліва направо
Адитивний + - Зліва направо
Зсув >> >>> << Зліва направо
Реляційний > >= < <= Зліва направо
Рівність == != Зліва направо
Побітове І (AND) & Зліва направо
Виключне АБО (XOR) ^ Зліва направо
Побітове АБО (OR) | Зліва направо
Логічне І (AND) && Зліва направо
Логічне АБО (OR) || Зліва направо
Умовний ?: Справа наліво
Присвоювання = += -= *= /= %= >>= <<= &= ^= |= Справа наліво
Кома , Зліва направо

У верхньому рядку розташовані найпріоритетніші оператори. Круглі дужки () використовуються для явного встановлення пріоритету. Квадратні дужки [] використовуються для індексування змінної-масиву. Оператор . використовується для отримання полів і методів від посилання на об'єкт або клас.

Що нижче оператори розташовані в таблиці, то нижче їхній пріоритет.

Якщо ви використовуєте у виразі кілька операторів, не лінуйтеся — ставте дужки.

Так, у Java можна написати щось на кшталт if (a & 1<<b > ~c), але так робити не варто. Ви пишете код не лише для компілятора, але й для інших програмістів. Що читабельнішим буде код, то краще.



3. Префіксний і постфіксний інкременти

Як ви вже знаєте, у Java є оператор інкременту (++) і оператор декременту (--), які збільшують і зменшують значення змінної на 1.

Однак ви, напевно, не знаєте, що є два види цих операцій: префіксні (оператор ставиться перед змінною) і постфіксні (оператор ставиться після змінної). І працюють ці оператори трохи по-різному.

У Java можна написати такий вираз:

int a = 5;
int b = a++;

Якщо оператор ++ стоїть після змінної та водночас ця змінна входить в якийсь вираз (як у прикладі вище), то у виразі буде використано поточне значення змінної, а тільки потім його буде збільшено на 1.

Інакше кажучи, відбудеться приблизно от що:

int a = 5;
int b = a;
a = a + 1;

Тобто b матиме значення 5, а не 6, як це могло здатися спочатку.

Якщо ж оператор ++ стоїть перед змінною і змінна входить в якийсь вираз, її значення спочатку буде збільшено на 1, а тільки потім використано у виразі.

int a = 5;
int b = ++a;

Приклад вище еквівалентний такому прикладу:

int a = 5;
a = a + 1;
int b = a;

Отут вже значення b дорівнюватиме 6.

Є навіть один приклад, який використовують Java-програмісти, щоб визначити, чи їхній співрозмовник — теж Java-програміст:

int a = 5;
int b = ++a++a;

Так, це теж правильний запис.

Цей приклад відмінно скомпілюється й перетвориться приблизно на таке:

int a = 5;

a = a + 1;
int v1 = a;

a = a + 1;
int v2 = a;

int b = v1 + v2;

Для оператора -- все відбувається аналогічно.


Коментарі (22)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Anonymous #3425794 Рівень 1
14 грудня 2024
Прошу уваги☺️ Цей коментарій не відповідь, а для того щоб ви зрозуміли, як воно працює. Все дуже просто. а = 3 b = А++ + (--А * А++); // останнє А++ нічого не набуває воно таке саме як і А, бо постінкремент; Значення А набувається зліва направо ігноруючи арифметичні оператори (+-*/) -перше А++ = 3, постдекремент перекидає одиничку на наступне А; -наступне (друге) --А отримало +1 від першого, але за рахунок предекремента одразу відняло -1 і стало дорівнювати 3 знову; -трете А++ нічого не отримає, бо постінкремент додасть до наступного A, а таких в нас немає(; Тепер розв'язок йде за звичними нашому мозку діями 3 + (3 * 3) = 12 Бажаю успіхів!!!
IronMan57 Рівень 28
1 грудня 2024
Ніяк не міг розібратись з порядком виконання операцій в останній задачі. Нарешті звернувся до ChatGPT за поясненням, давши йому тільки дві початкові стрічки коду, задані в завданні (не в розв'язку): int a = 3; int b = a++ + (--a * a++); І... сюрприз - ChatGPT написав, що в результаті виконання цих команд змінна b матиме значення 11. Прийшлось його тицнюти носом в сліди його ж життєдіяльності. Після чого ChatGPT перевзувся, вибачився і написав, що все таки буде 12 і дав слідуюче пояснення: Пошаговый разбор выражения int b = a++ + (--a * a++); Начальное значение a = 3. Операция a++: Постфиксный инкремент. Возвращается текущее значение a, затем оно увеличивается. Возвращаемое значение: 3. Значение a становится 4. Операция --a: Префиксный декремент. Уменьшает значение a перед использованием. Значение a становится 3. Возвращаемое значение: 3. Операция a++: Постфиксный инкремент. Возвращается текущее значение a, затем оно увеличивается. Возвращаемое значение: 3. Значение a становится 4. Вычисление --a * a++: После декремента значение a равно 3. Умножение: 3 * 3 = 9. Сложение: Суммируется результат первого постинкремента (3) и результата умножения (9). Результат: 3 + 9 = 12. Присваивание: Переменной b присваивается значение 12. Итог: Значение переменной b: 12. Значение переменной a после выполнения выражения: 4. Ошибка в моём разборе: Я неправильно учёл изменение значения переменной a при постинкрементах и декременте, что привело к ошибке в интерпретации результата умножения и сложения. Правильная последовательность операций: Операция a++ (возвращает 3, a становится 4). Операция --a (уменьшает a до 3, возвращает 3). Операция a++ (возвращает 3, a становится 4). Умножение --a * a++ (результат: 3 * 3 = 9). Сложение a++ + (...) (результат: 3 + 9 = 12). Присваивание значения b.
IronMan57 Рівень 28
1 грудня 2024
Після того, як я попросив уточнити, яка з операцій a++ (у виразі їх дві) виконується першою, він ще двічі перевзувався, даючи різні кінцеві відповіді. Після згадався анекдот: "Зустрілись два політологи: - Що взагалі відбувається? - Зараз я тобі все поясню. - Пояснити-то я й сам можу. Я тебе запитую: Що, #$&, відбувається?"
Гаркін Рівень 14
20 березня 2024
Задачу я вирішив, але що за чим йде у цьому рядку

number < 15 & number > 25 & (number += 15) < 25
я не розумію. Сподіваюсь, що вирішив усі задачі лекції я розберусь з цим (і зможу це написати). Буду вдячний, якщо хтось пояснить цей рядок.
Гаркін Рівень 14
22 березня 2024
Дивимось пріоритет операцій та лекцію з додаткових матеріалів "Побитовые операции в Java" https://javarush.com/groups/posts/1925-pobitovihe-operacii . number < 15 & number > 25 & (number += 15) < 25 пріоритет операції у дужках потім пріоритет у порівнянь, тобто number < 15 це false number > 25 це false 30 < 25 це false отримаємо false & false & false Для перевірки результату я створив: boolean a = false; boolean c = true; boolean b = a & a & a; System.out.println(b); А який результат? А спробуйте :) . Ну і задля експерименту c & c & a А чому такі результати? Ось відповідь: … The Java Virtual Machine encodes boolean array components using 1 to represent true and 0 to represent false. …
gummer Рівень 11
6 березня 2024
Я не розумію. В мене виходить 20, але задачу перевірку не проходить оО

int b = ++a + (a++ * --a);
Апд.: не стримався та глянув правильну відповідь

int b = ++a + (a-- * ++a);
Вибачаюсь, а ви колись про комутативність множення чули? Т_Т
Гаркін Рівень 14
22 березня 2024

У методі можна змінювати лише постінкремент на преінкремент
 і навпаки, а також постдекремент на предекремент і навпаки.
Тобто ти порушив умови завдання.
4 лютого 2024
Решал так: В каждом случае мы можем просто менять с одной позиции на другую (пост/пред). При этом есть только два значения в итоге. Пробежался по 3 переменным, у которых в конечном итоге было по 2 варианта. Что-то вроде: 3 || 4 + (3 || 4 * 3 || 4) = 20 (тут "||" я написал как "или"). Решая математический ребус получаем 4+(4*4) = 20. Осталось написать код. З.Ы. Помог сильно в решении первый запуск. Думал 7, по факту 12. Пробежался по логике, поправился и вуаля.
Serhii Horban Рівень 18
11 липня 2023
логіка компілятора така: int a = 3; /*int b = ++a + (a-- * ++a); цей вираз можна розбити на 3 менших вирази (v1 + (v2 * v3)) */ a = a + 1;// (++а) спочатку збільшуєм а на 1 int v1 = a;// надаємо значення першому виразу int v2 = a;// надаємо значення другому виразу a = a - 1;// (а--) зменшуєм а на 1 a = a + 1;//(а++) збільшуєм а на 1 int v3 = a;// надаємо значення третьому виразу int b = v1 + (v2 * v3);// а тут уже іде нормальний пріоритет І виходить що, префіксний і постфіксний інкремент і декремент взагалі поза пріотритетом?
Anonymous #3289637 Рівень 19
24 квітня 2023
int a = 3; int b = ++a + (a-- * ++a); повинно бути 16 ? Але мене написало що вийшло 20 та пропустило задачу. мб я чогось не розумію
Viacheslav B. Рівень 1
10 лютого 2024
зверні увагу що а-- це постфіксний інкремент, як пишут у лекції - Якщо оператор ++ або -- стоїть після змінної та водночас ця змінна входить в якийсь вираз (як у прикладі вище), то у виразі буде використано поточне значення змінної, а тільки потім його буде збільшено++ або зменшено на 1. тобто (a-- * ++a) - це (4 * 4)
Abver Рівень 4 Expert
18 грудня 2022
Я думав що зрозумів приоритетність, але походу ні. От поясніть мені хтось, int a = 3; int b = ++a + (a * a); чому результат 20. я думав що спочатку 3*3=9 і потім +4 але щось я неправильно зрозумів
Алексей Рівень 40
21 грудня 2022
int b = a++ = (a*a) Це теж саме, що a=a+1; a + (a*a)
Yaroslav Tkachyk Рівень 23 Expert
24 грудня 2022
Якщо коротко: 1) в цій лекції є пріоритет операцій. 2) Операції в своїй переважній більшості виконуються зліва направо. 3) щоб не писати вірний код - оформлю так: операція №1 - префіксний інкремент числа а - число а збільшено на одиницю операція №2 - (в дужках результат операції №1 і постфіксний декремент) - число а спочатку використано, а потім зменшено на одиницю)) операція №3 - префіксний інкремент результату операції №2 - число а спочатку збільшено на одиницю а потім стає результатом операції №3 операція №4 - операція множення в дужках результату операції №2 та результату операції №3. операція №5 - тут не впевнений в черговості: варіант (а) - чи спочатку int b присвоюється результат операції №1 (тоді скажемо це буде крок №1.5) і потім відбувається додавання результату операції №4. варіант (б) - відбувається сумування результатів операцій №1 та №4. І тоді вже крок №6 - це присвоювання результату операції №5 як значення для змінної b. Може хто підкаже чи є функціонал в IDEA щоб проглянути виконання виразу покроково, щось на кшталт перегляду покроковості циклу під час використання дебагера?
Roma Chernesh Рівень 16
25 грудня 2022
Поясніть хтось, хто це розуміє (бо сам аніяк не вкумекаю) Якщо запустити код без змін, то він видає 12. АЛЕ: a = 3; a++ + (--a * a++); Хіба це не так працює? 1) --а = 2; 2) a++ = 3; 3) --a * a++ = 2 * 3 = 6; 4) a++ = 4; 5) a++ + (--a * a++) = 4 + ( 2 * 3) = 10 Тоді звідки 12? Задачу-то вирішив методом научного тику (три всього змінні). Але щось логіку не зрозумів: - В нас же спочатку йдуть інкріменти у душках. (1 , 2) - Потім вони перемножаються. (3) І потім у кніці додаємо це до інкріменту. (4, 5) Хіба ні?
Yaroslav Tkachyk Рівень 23 Expert
26 грудня 2022
Спочатку виконуємо операцію після знаку =. a = 3; b = a++ + (--a * a++); Послідовність кроків наступна: 1) b = а (тобто 3) 2) а++ (а стає 4) 3) пішли операції в дужках - --а( а стає 3) 4) операція множення а*а (добуток в дужках стає 9) 5) а++ (а стає 4) 6) остання операція додавання b + добуток в дужках (3+9) 7) Результат 12.
Yaroslav Tkachyk Рівень 23 Expert
26 грудня 2022
в тебе в 3 дії (--a * a++ = 2 * 3 = 6;) є одразу неточність, оскільки: якщо початково а == 3, то логіка дії в дужках наступна: --а (а = а-1; а == 2) а*а = 4 а++ (а = а+1; а == 3)
Roma Chernesh Рівень 16
26 грудня 2022
Величезне спасибі! Все думав-гадав, чи дужки "( )" мають перевагу над ++ чи ні. Ото тепер все стало на свої місця!
777 Рівень 16
23 вересня 2022
хто мені пояснить чому цей код не прходить провірку? int a = 3; int b = ++a + (a++ * --a);
Саша Рівень 30
9 жовтня 2022
в дужках має бути префінкремент і постдискремент. А в тебе зараз виходить б = 10
Yaroslav Tkachyk Рівень 23 Expert
24 грудня 2022
Якраз його код дасть результат 20. Проте не виконана умова: у методі можна змінювати лише постінкремент на преінкремент і навпаки, а також постдекремент на предекремент і навпаки.
Lipovskyi Volodymyr Рівень 36
11 травня 2022
Після попередньої лекції просто бальзам на душу)))