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

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

Відкрита

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) не виконується.

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

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


9
Задача
Java Syntax Zero,  9 рівень,  7 лекція
Недоступна
Логічні оператори
Логічні оператори

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

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

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

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

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

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

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

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

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


9
Задача
Java Syntax Zero,  9 рівень,  7 лекція
Недоступна
Пріоритети
Пріоритети

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;

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


9
Задача
Java Syntax Zero,  9 рівень,  7 лекція
Недоступна
Інкременти
Інкременти
Коментарі (22)
  • популярні
  • нові
  • старі
Щоб залишити коментар, потрібно ввійти в систему
Anonymous #3425794
Рівень 1
14 грудня 2024, 15:58
Прошу уваги☺️ Цей коментарій не відповідь, а для того щоб ви зрозуміли, як воно працює. Все дуже просто. а = 3 b = А++ + (--А * А++); // останнє А++ нічого не набуває воно таке саме як і А, бо постінкремент; Значення А набувається зліва направо ігноруючи арифметичні оператори (+-*/) -перше А++ = 3, постдекремент перекидає одиничку на наступне А; -наступне (друге) --А отримало +1 від першого, але за рахунок предекремента одразу відняло -1 і стало дорівнювати 3 знову; -трете А++ нічого не отримає, бо постінкремент додасть до наступного A, а таких в нас немає(; Тепер розв'язок йде за звичними нашому мозку діями 3 + (3 * 3) = 12 Бажаю успіхів!!!
IronMan57
Рівень 28
1 грудня 2024, 15:31
Ніяк не міг розібратись з порядком виконання операцій в останній задачі. Нарешті звернувся до 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, 20:30
Після того, як я попросив уточнити, яка з операцій a++ (у виразі їх дві) виконується першою, він ще двічі перевзувався, даючи різні кінцеві відповіді. Після згадався анекдот: "Зустрілись два політологи: - Що взагалі відбувається? - Зараз я тобі все поясню. - Пояснити-то я й сам можу. Я тебе запитую: Що, #$&, відбувається?"
Гаркін
Рівень 14
20 березня 2024, 20:27
Задачу я вирішив, але що за чим йде у цьому рядку
number < 15 & number > 25 & (number += 15) < 25
я не розумію. Сподіваюсь, що вирішив усі задачі лекції я розберусь з цим (і зможу це написати). Буду вдячний, якщо хтось пояснить цей рядок.
Гаркін
Рівень 14
22 березня 2024, 18:57
Дивимось пріоритет операцій та лекцію з додаткових матеріалів "Побитовые операции в 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 Український ютубер в gummerGames
6 березня 2024, 16:01
Я не розумію. В мене виходить 20, але задачу перевірку не проходить оО
int b = ++a + (a++ * --a);
Апд.: не стримався та глянув правильну відповідь
int b = ++a + (a-- * ++a);
Вибачаюсь, а ви колись про комутативність множення чули? Т_Т
Гаркін
Рівень 14
22 березня 2024, 18:12
У методі можна змінювати лише постінкремент на преінкремент
 і навпаки, а також постдекремент на предекремент і навпаки.
Тобто ти порушив умови завдання.
4 лютого 2024, 21:09
Решал так: В каждом случае мы можем просто менять с одной позиции на другую (пост/пред). При этом есть только два значения в итоге. Пробежался по 3 переменным, у которых в конечном итоге было по 2 варианта. Что-то вроде: 3 || 4 + (3 || 4 * 3 || 4) = 20 (тут "||" я написал как "или"). Решая математический ребус получаем 4+(4*4) = 20. Осталось написать код. З.Ы. Помог сильно в решении первый запуск. Думал 7, по факту 12. Пробежался по логике, поправился и вуаля.
Serhii Horban
Рівень 18
11 липня 2023, 19:34
логіка компілятора така: 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, 21:42
int a = 3; int b = ++a + (a-- * ++a); повинно бути 16 ? Але мене написало що вийшло 20 та пропустило задачу. мб я чогось не розумію
Viacheslav B. System Administrator
10 лютого 2024, 20:41
зверні увагу що а-- це постфіксний інкремент, як пишут у лекції - Якщо оператор ++ або -- стоїть після змінної та водночас ця змінна входить в якийсь вираз (як у прикладі вище), то у виразі буде використано поточне значення змінної, а тільки потім його буде збільшено++ або зменшено на 1. тобто (a-- * ++a) - це (4 * 4)
Abver
Рівень 4
Expert
18 грудня 2022, 21:17
Я думав що зрозумів приоритетність, але походу ні. От поясніть мені хтось, int a = 3; int b = ++a + (a * a); чому результат 20. я думав що спочатку 3*3=9 і потім +4 але щось я неправильно зрозумів
Алексей
Рівень 40
21 грудня 2022, 13:17
int b = a++ = (a*a) Це теж саме, що a=a+1; a + (a*a)
Yaroslav Tkachyk
Рівень 23
Expert
24 грудня 2022, 21:49
Якщо коротко: 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, 19:44
Поясніть хтось, хто це розуміє (бо сам аніяк не вкумекаю) Якщо запустити код без змін, то він видає 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, 17:51
Спочатку виконуємо операцію після знаку =. 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, 17:55
в тебе в 3 дії (--a * a++ = 2 * 3 = 6;) є одразу неточність, оскільки: якщо початково а == 3, то логіка дії в дужках наступна: --а (а = а-1; а == 2) а*а = 4 а++ (а = а+1; а == 3)
Roma Chernesh
Рівень 16
26 грудня 2022, 18:40
Величезне спасибі! Все думав-гадав, чи дужки "( )" мають перевагу над ++ чи ні. Ото тепер все стало на свої місця!
777
Рівень 16
23 вересня 2022, 17:38
хто мені пояснить чому цей код не прходить провірку? int a = 3; int b = ++a + (a++ * --a);
Саша
Рівень 30
9 жовтня 2022, 02:16
в дужках має бути префінкремент і постдискремент. А в тебе зараз виходить б = 10
Yaroslav Tkachyk
Рівень 23
Expert
24 грудня 2022, 21:23
Якраз його код дасть результат 20. Проте не виконана умова: у методі можна змінювати лише постінкремент на преінкремент і навпаки, а також постдекремент на предекремент і навпаки.
Lipovskyi Volodymyr
Рівень 36
11 травня 2022, 20:24
Після попередньої лекції просто бальзам на душу)))