Логические операторы в Java — это операторы, которые принимают значения типа boolean и возвращают boolean: ! (НЕ), && и & (И), || и | (ИЛИ), ^ (исключающее ИЛИ). Из них собирают условия для if, while и тернарного оператора. Главная практическая разница — между &&/|| (вычисляют правый операнд только при необходимости) и &/| (вычисляют оба всегда).
Содержание
Ниже — таблица истинности, короткое замыкание и защита от NullPointerException, приоритет, тернарный оператор и типичные ошибки. Все примеры проверены на OpenJDK 25.0.4 (Java 25 LTS) в сентябре 2026.
Мини-словарь: что с чем не путать
Одни и те же символы в Java означают разное в зависимости от типа операндов, поэтому сначала термины:
| Термин | Операторы | Операнды | Что делает |
|---|---|---|---|
| Условные логические (с коротким замыканием) | &&, || |
только boolean |
правый операнд вычисляется, только если от него зависит результат |
| Логические без сокращения | &, |, ^ |
boolean |
всегда вычисляют оба операнда |
| Побитовые | &, |, ^, ~ |
целые (int, long и др.) |
работают с каждым битом числа |
| Логическое отрицание | ! |
boolean |
меняет true на false и наоборот |
| Операторы сравнения | ==, !=, <, >, <=, >= |
числа (==, != — еще и ссылки) |
не логические, но дают boolean, который потом комбинируют логическими |
Выражение 5 & 3 — побитовое И двух чисел (результат 1), а true & false — логическое И (результат false). Побитовые операции — отдельная тема, здесь только логические.
Таблица истинности: полный пример
Программа перебирает все сочетания двух значений и печатает результат каждого оператора:
public class TruthTable {
public static void main(String[] args) {
boolean[] values = {false, true};
System.out.println("a b | a&&b a||b a^b !a");
for (boolean a : values) {
for (boolean b : values) {
System.out.printf("%-5b %-5b | %-5b %-5b %-5b %-5b%n",
a, b, a && b, a || b, a ^ b, !a);
}
}
}
}
Запуск без отдельной компиляции (Java 11+): java TruthTable.java. Вывод:
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
Как читать таблицу:
- И (
&&,&) —true, только когда оба операндаtrue. - ИЛИ (
||,|) —false, только когда оба операндаfalse. - Исключающее ИЛИ (
^) —true, когда операнды разные. Дляbooleanзаписьa ^ bдает то же, чтоa != b. - НЕ (
!) — унарный оператор, у него один операнд.
Для & и | таблица та же, что для && и ||: различается не результат, а порядок вычисления. Полную теорию (импликация, эквивалентность, построение таблиц для сложных формул) разбирает статья калькулятор истинности и логика для программиста.
Короткое замыкание: && и || против & и |
Короткое замыкание (short-circuit evaluation) — правило, по которому && и || не вычисляют правый операнд, если результат уже известен по левому:
false && X— всегдаfalse,Xне вычисляется;true || X— всегдаtrue,Xне вычисляется.
Проверим счетчиком вызовов:
public class ShortCircuit {
static int calls = 0;
static boolean check(String name, boolean result) {
calls++;
System.out.println(" вызван " + name);
return result;
}
public static void main(String[] args) {
System.out.println("false && ...:");
boolean r1 = check("левый", false) && check("правый", true);
System.out.println(" результат " + r1 + ", вызовов " + calls);
calls = 0;
System.out.println("false & ...:");
boolean r2 = check("левый", false) & check("правый", true);
System.out.println(" результат " + r2 + ", вызовов " + calls);
calls = 0;
System.out.println("true || ...:");
boolean r3 = check("левый", true) || check("правый", false);
System.out.println(" результат " + r3 + ", вызовов " + calls);
}
}
false && ...:
вызван левый
результат false, вызовов 1
false & ...:
вызван левый
вызван правый
результат false, вызовов 2
true || ...:
вызван левый
результат true, вызовов 1
Результат у && и & одинаковый, но с & правый метод все равно выполнился. Если в правом операнде есть побочный эффект (запись в базу, i++, сетевой вызов), от выбора оператора зависит поведение программы, а не только скорость. У ^ сокращенной формы нет: чтобы узнать, различаются ли операнды, нужны оба.
Защита от NullPointerException
Самое частое применение короткого замыкания — проверка на null перед обращением к объекту. Сначала неверный вариант с &:
public class NullGuard {
public static void main(String[] args) {
String name = null;
if (name != null && !name.isBlank()) {
System.out.println("Привет, " + name);
} else {
System.out.println("Имя не задано");
}
if (name != null & !name.isBlank()) {
System.out.println("Привет, " + name);
}
}
}
Результат: первый if отработал, второй упал.
Имя не задано
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.isBlank()" because "<local1>" is null
at NullGuard.main(NullGuard.java:11)
С && вызов name.isBlank() не выполняется, потому что name != null уже дал false. С & Java вычисляет оба операнда и вызывает метод у null. Исправление — &&, и проверка на null обязательно слева: !name.isBlank() && name != null упадет так же. Вместо имени переменной в тексте исключения стоит "<local1>": так бывает при запуске java NullGuard.java и при javac без отладочной информации. Если скомпилировать с javac -g, сообщение назовет переменную: because "name" is null.
Когда & и | для boolean все же нужны: если оба операнда обязаны выполниться (например, провалидировать все поля формы и собрать все ошибки, а не остановиться на первой). Такой код лучше дополнить комментарием, иначе коллега примет & за опечатку.
Приоритет логических операторов
Приоритет определяет, как выражение без скобок группируется (сверху — связывает сильнее). Сами операнды Java вычисляет слева направо, а приоритет лишь решает, к какому оператору какой операнд относится.
| Приоритет | Операторы | Пример |
|---|---|---|
| 1 | ! (унарный) |
!a |
| 2 | арифметика * / %, затем + - |
x + 1 |
| 3 | сравнение < > <= >= |
age >= 18 |
| 4 | равенство == != |
a == b |
| 5 | & |
a & b |
| 6 | ^ |
a ^ b |
| 7 | | |
a | b |
| 8 | && |
a && b |
| 9 | || |
a || b |
| 10 | тернарный ?: |
c ? x : y |
| 11 | присваивание = &= |= ^= |
ok &= f |
Таблица сокращенная: в нее не вошли сдвиги << >>, instanceof, инкременты и лямбды. Главное из нее: && связывает сильнее, чем ||, так же как умножение сильнее сложения.
public class Precedence {
public static void main(String[] args) {
boolean a = true, b = false, c = false;
System.out.println(a || b && c); // a || (b && c)
System.out.println((a || b) && c);
System.out.println(!a == b); // (!a) == b
System.out.println(a | b & c); // a | (b & c)
System.out.println(a ^ b | c); // (a ^ b) | c
int age = 25;
boolean hasTicket = false, isStaff = true;
System.out.println(age >= 18 && hasTicket || isStaff); // (age >= 18 && hasTicket) || isStaff
System.out.println(age >= 18 && (hasTicket || isStaff));
}
}
Вывод: true, false, true, true, true, true, true. Первые две строки показывают, что скобки меняют результат. Последние две совпали на этих данных случайно: при age = 15 первое выражение даст true (сотрудник пройдет в любом возрасте), второе — false. Если условие смешивает && и ||, скобки лучше ставить явно, даже когда приоритет и так дает нужный порядок.
Как упростить отрицание сложного условия
Законы де Моргана позволяют внести ! внутрь скобок: !(a && b) равно !a || !b, а !(a || b) равно !a && !b. Пример: «магазин закрыт» — это !(hour >= 9 && hour < 21), или без отрицания hour < 9 || hour >= 21. Второй вариант читается легче, и его проще покрыть тестом на границы (8, 9, 20, 21).
Тернарный оператор коротко
Тернарный оператор условие ? значение1 : значение2 возвращает первое значение, если условие true, иначе второе. Он тоже вычисляет только одну ветку.
public class Ternary {
public static void main(String[] args) {
int books = 14;
String status = books >= 12 ? "план выполнен" : "еще читать";
System.out.println(status);
books = 11;
String level = books >= 12 ? "план выполнен"
: books > 10 ? "почти"
: "еще читать";
System.out.println(level);
boolean ok = true;
ok &= books > 20;
System.out.println(ok);
ok |= books > 10;
System.out.println(ok);
}
}
Вывод: план выполнен, почти, false, true. Тернарный оператор уместен, когда нужно выбрать значение для переменной или return; если в ветках действия, а не значения, или вложенность больше двух уровней — понятнее if/else. Составные &=, |= и ^= для boolean не сокращаются: правая часть вычисляется всегда. Операторов &&= и ||= в Java нет.
Типичные ошибки
1. == вместо equals для строк. Оператор == сравнивает ссылки, а не содержимое.
import java.util.Objects;
public class Mistakes {
public static void main(String[] args) {
String typed = new String("java");
System.out.println(typed == "java");
System.out.println(typed.equals("java"));
System.out.println("java".equals(null));
System.out.println(Objects.equals(null, null));
boolean isAdmin = false;
if (isAdmin = true) {
System.out.println("Доступ открыт");
}
System.out.println(isAdmin);
System.out.println(5 & 3);
System.out.println(true & false);
}
}
Вывод: false, true, false, true, Доступ открыт, true, 1, false. Строки с одинаковым текстом дали false через ==. Исправление — equals, а если значение может быть null, то "java".equals(x) (литерал слева) или Objects.equals(a, b).
2. = вместо == в условии. Для boolean это компилируется: isAdmin = true присваивает значение и возвращает его, поэтому ветка выполнилась, а флаг испорчен. Для int такая опечатка не скомпилируется. Исправление — писать просто if (isAdmin), без сравнения с true.
3. & вместо &&. Для boolean результат тот же, но нет короткого замыкания: отсюда NullPointerException из раздела выше и лишние вызовы методов. Для целых чисел & — уже побитовая операция (5 & 3 дает 1).
4. Логический оператор с числом. В Java нет неявного перевода int в boolean, как в C. Код if (count && true) при int count = 3 не компилируется:
BadOperand.java:4: error: bad operand types for binary operator '&&'
if (count && true) {
^
first type: int
second type: boolean
1 error
Исправление — явное сравнение: if (count > 0 && flag).
Выводы
- Логические операторы Java работают только с
boolean:!,&&,||,&,|,^; для целых чисел&,|,^становятся побитовыми. &&и||вычисляют правый операнд только при необходимости; на этом строится проверкаx != null && x.method().&и|наbooleanвычисляют оба операнда — используйте их, только когда нужны побочные эффекты обеих частей.&&приоритетнее||; в смешанных условиях ставьте скобки явно.- Строки сравнивают через
equalsилиObjects.equals, а не==.
Где применяется / связь с практикой
Логические выражения — основа любой бизнес-логики: проверка прав доступа, валидация форм, фильтры в Stream API (filter(u -> u.isActive() && u.getAge() >= 18)), условия циклов и защита от null. Ошибки в них — частая причина багов, которые не ловит компилятор: код работает, но пропускает не тех пользователей.
Освойте тему на практике
Если хочется системно пройти синтаксис, ООП и коллекции с проверкой домашних заданий, подойдет курс Java разработчик. Базовый уровень. Разобрать отдельные темы с преподавателями можно на бесплатных открытых уроках.
FAQ
Быстрее ли &&, чем &?
Иногда да, потому что правый операнд может не вычисляться, но выбирать оператор стоит по смыслу, а не ради скорости. Разница заметна, только если правая часть дорогая (вызов метода, запрос).
Есть ли в Java логический XOR с коротким замыканием?
Нет: для XOR нужны оба операнда. Для boolean вместо a ^ b можно писать a != b — результат одинаковый.
Можно ли применить ! к Boolean, который равен null?
Нет. При распаковке Boolean в boolean значение null дает NullPointerException; безопасный вариант — Boolean.TRUE.equals(flag).



