Логические операторы в Java
Логические операторы в Java выполняются над операндами типа boolean и возвращают логическое значение — true или false. Именно из них строятся сложные условия для оператора if и циклов: И (&, &&), ИЛИ (|, ||), исключающее ИЛИ (^) и НЕ (!).
Таблица логических операторов
Следующая таблица перечисляет логические операторы языка Java:
| Оператор | Описание | Пример |
|---|---|---|
| & | Логическое И (AND), конъюнкция | true & false → false |
| | | Логическое ИЛИ (OR), дизъюнкция | true | false → true |
| ^ | Исключающее ИЛИ (XOR) | true ^ true → false |
| ! | Унарное НЕ (NOT), инверсия | !true → false |
| && | Укороченное И (short-circuit AND) | false && x → false, x не вычисляется |
| || | Укороченное ИЛИ (short-circuit OR) | true || x → true, x не вычисляется |
| == | Проверка на равенство | true == false → false |
| != | Проверка на неравенство | true != false → true |
| &= | И с присваиванием | a &= b ≡ a = a & b |
| |= | ИЛИ с присваиванием | a |= b ≡ a = a | b |
| ^= | Исключающее ИЛИ с присваиванием | a ^= b ≡ a = a ^ b |
Приоритет логических операторов — от высшего к низшему: !, затем &, ^, |, && и, наконец, ||. Поэтому выражение a || b && c вычисляется как a || (b && c). Если есть сомнения — расставляйте скобки явно.
Операторы AND, OR, XOR, NOT и таблица истинности
Начнём с операторов OR (|), AND (&), XOR (^) и NOT (!). Операторы OR, AND и XOR — бинарные: им требуются два операнда. NOT — унарный оператор: в операции участвует только один операнд. Результаты выполнения этих операций сведены в таблицу истинности:
| A | B | A & B | A | B | A ^ B | !A |
|---|---|---|---|---|---|
| false | false | false | false | false | true |
| false | true | false | true | true | true |
| true | false | false | true | true | false |
| true | true | true | true | false | false |
Укороченные операторы && и || дают точно такие же результаты, как & и |, — различие только в порядке вычисления операндов (см. следующий раздел).
OR (|) — результат true, если хотя бы один операнд равен true. Пример: чтобы забрать ребёнка из садика, должна прийти либо мать, либо отец, либо оба — в любом случае результат положительный. Если не придёт никто, ребёнка не заберут — результат отрицательный.
AND (&) — результат true, только если и A, и B равны true. Пример: чтобы свадьба состоялась, и невеста (A), и жених (B) должны явиться на бракосочетание, иначе она не состоится.
XOR (^) — результат true, только если операнды различны: ровно один из них равен true. Пример: у двух друзей один велосипед на двоих — поездка состоится, только если поедет кто-то один. Вдвоём они ехать не могут, а если не поедет никто, поездки тоже не будет.
NOT (!) — инвертирование значения: true становится false, и наоборот.
Рассмотрим пример использования логических операторов:
public class BooleanLogic1 {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
boolean c = a | b;
boolean d = a & b;
boolean e = a ^ b;
boolean f = (!a & b) | (a & !b);
boolean g = !a;
System.out.println("a = " + a); // true
System.out.println("b = " + b); // false
System.out.println("a | b = " + c); // true
System.out.println("a & b = " + d); // false
System.out.println("a ^ b = " + e); // true
System.out.println("(!a & b) | (a & !b) = " + f); // true
System.out.println("!a = " + g); // false
}
} Обратите внимание: те же символы &, |, ^, применённые к целочисленным операндам, выполняют побитовые операции над их двоичным представлением — это отдельная тема.
Укороченные операторы && и || (short-circuit)
Чаще всего в Java используются так называемые укороченные логические операторы (short-circuit): && — укороченное И и || — укороченное ИЛИ. В формальной спецификации языка Java они называются условными операторами (conditional-and, conditional-or).
Правый операнд укороченной операции вычисляется только тогда, когда от него зависит результат: для && — если левый операнд равен true, для || — если левый операнд равен false. В противном случае результат уже известен, и правый операнд пропускается.
В следующем примере правый операнд num / d > 10 вычисляться не будет: условие d != 0 ложно, значит результат всего выражения — false, и деление на ноль не выполняется:
public class BooleanLogic2 {
public static void main(String[] args) {
int d = 0;
int num = 10;
if (d != 0 && num / d > 10) {
System.out.println("num = " + num);
}
}
} Если же записать это выражение с обычным оператором — d != 0 & num / d > 10, — правый операнд будет вычислен в любом случае, и программа завершится исключением времени выполнения ArithmeticException: / by zero (целочисленное деление на ноль).
Тот же приём защищает от NullPointerException — это один из самых частых практических паттернов в Java:
String s = null;
if (s != null && !s.isEmpty()) { // s.isEmpty() не вызывается, NPE нет
System.out.println(s);
} Важно
Не путайте & и && (а также | и ||): результат у них одинаковый, но одиночные операторы всегда вычисляют оба операнда, а укороченные могут пропустить правый. По умолчанию в условиях используйте && и ||; одиночные & и | нужны лишь тогда, когда правый операнд обязан выполниться в любом случае — например, содержит вызов метода с нужным побочным эффектом.
Сравнение boolean: == и !=
Чтобы сравнить два значения типа boolean, используются операторы сравнения == (проверка на равенство) и != (проверка на неравенство):
public class BooleanLogic4 {
public static void main(String[] args) {
boolean b1 = true;
boolean b2 = false;
System.out.println(b1 == b2); // false
System.out.println(b1 != b2); // true
}
} Заметьте, что для boolean оператор != даёт тот же результат, что и ^: true, когда операнды различны. Сравнивать boolean с числами нельзя — выражение true == 1 в Java не компилируется.
Операторы с присваиванием: &=, |=, ^=
Для операторов AND, OR и XOR существуют составные операторы присваивания. Запись a &= b эквивалентна a = a & b:
public class BooleanLogic5 {
public static void main(String[] args) {
boolean b1 = true;
boolean b2 = true;
b1 &= b2; // равносильно b1 = b1 & b2;
System.out.println(b1); // true
b1 |= b2; // равносильно b1 = b1 | b2;
System.out.println(b1); // true
b1 ^= b2; // равносильно b1 = b1 ^ b2;
System.out.println(b1); // false
}
} Операторов &&= и ||= в Java не существует — составные присваивания есть только для одиночных &, |, ^, и правый операнд в них вычисляется всегда.
Типичные ловушки
Если нужно проверить, попадает ли переменная в диапазон значений, математическая запись a < x < b в Java не компилируется. Такое условие разбивается на два сравнения, соединённых оператором &&: a < x && x < b:
public class BooleanLogic3 {
public static void main(String[] args) {
int a = 1;
int b = 2;
int x = 3;
System.out.print(a < x && x < b); // false: 3 не лежит между 1 и 2
// System.out.print(a < x < b); // Ошибка компиляции!
}
} Важно
Запись a < x < b не работает, потому что выражение вычисляется слева направо: сначала a < x даёт boolean, а затем компилятор пытается сравнить boolean с числом b — такой операции в Java нет. Всегда пишите a < x && x < b.
Ещё две ситуации, которые регулярно встречаются на собеседованиях:
// 1. Приоритет: && выше, чем ||
boolean r = true || false && false; // true: вычисляется как true || (false && false)
// 2. Одиночный & не защищает от исключения
String s = null;
// if (s != null & !s.isEmpty()) {} // NullPointerException: правый операнд вычисляется всегда Часто задаваемые вопросы
Чем отличается && от & в Java?
Для операндов boolean оба оператора дают одинаковый результат, но && работает по схеме короткого замыкания: если левый операнд равен false, правый не вычисляется вовсе. Одиночный & всегда вычисляет оба операнда, а для целых чисел выполняет побитовое И. В условиях по умолчанию используйте &&.
Что такое короткое замыкание (short-circuit evaluation)?
Это порядок вычисления, при котором правый операнд && или || вычисляется только тогда, когда от него зависит результат. Так, в выражении s != null && s.isEmpty() метод isEmpty() не будет вызван при s == null, что защищает от NullPointerException. В спецификации Java эти операторы называются условными.
Почему выражение a < x < b не компилируется в Java?
Выражение вычисляется слева направо: a < x даёт значение типа boolean, после чего компилятор пытается сравнить boolean с числом b, а такая операция в Java запрещена. Проверку диапазона записывают двумя сравнениями через И: a < x && x < b.
Есть ли в Java операторы &&= и ||=?
Нет. Составные операторы присваивания существуют только для одиночных логических операторов: &=, |= и ^=. Они не используют короткое замыкание — правая часть вычисляется всегда. Если нужна укороченная семантика, пишите полную форму: a = a && b.
Презентацию с видео можно скачать на Patreon.
Видео объяснение
Предпочитаете видеоформат? Посмотрите этот урок с примерами и объяснениями.
Комментарии