Операторы и циклы в Java
Перед чтением: Операторы — общие понятия оператора, операнда, приоритетов; побитовые операторы — что такое побитовая операция и чем она отличается от логической.
Сначала: Циклы в коде — общая идея повторений, виды циклов и типичные ошибки без привязки к синтаксису языка.
Операторы и циклы в Java
Виды операторов
Операторы можно разделить на несколько видов:
Если вы только начинаете, полезно воспринимать операторы как "глаголы" языка:
- арифметические меняют числа;
- логические принимают решения;
- присваивания изменяют состояние переменной;
- условные выбирают ветку выполнения. Так проще перейти от заучивания таблицы к пониманию, как эти конструкции работают вместе в реальном коде.
| Тип | Примеры |
|---|---|
| Арифметические | + — сложение, - — вычитание, * — умножение, / — деление, % — остаток от деления |
| Сравнения | == — равно, != — не равно, > — больше, < — меньше, >= — больше или равно, <= — меньше или равно |
| Логические | ! — отрицание (NOT), & — конъюнкция (AND), | — дизъюнкция (OR), ^ — исключающее ИЛИ (XOR), && — сокращённая конъюнкция, || — сокращённая дизъюнкция, ~ — побитовое дополнение (NOT) |
| Присваивания | =, +=, -=, *=, /= |
| Тернарный | условие ? значение_если_истина : значение_если_ложь |
| Условные операторы | if-else, switch |
| Прочие | ++ — инкремент (увеличение на 1), -- — декремент (уменьшение на 1), // — однострочный комментарий, /* */ — многострочный комментарий |
Play ITЗагрузка интерактивного демо…
Сравнение
Для примитивных типов (например, int, double) оператор == сравнивает значения.
Для объектов (например, строк или пользовательских классов) оператор == сравнивает ссылки на объекты, то есть их физическое местоположение в памяти.
Чтобы сравнить содержимое объектов, используется метод .equals().
На практике правило простое — всё, что относится к бизнес-данным (String, UUID, сущности, DTO), сравнивайте через equals() или специализированные методы (compareTo, Comparator). Оператор == оставляйте для примитивов и редких случаев проверки идентичности ссылки.
В Java есть методы, которые выполняют функции, аналогичные операторам:
.equals()— аналог оператора == для сравнения содержимого объектов..compareTo()— используется для сравнения строк или объектов, реализующих интерфейс Comparable;Math.addExact(),Math.subtractExact(),Math.multiplyExact()— аналоги операторов+,-,*, но с проверкой на переполнение. Если результат выходит за пределы допустимых значений, выбрасывается исключение ArithmeticException;Integer.bitCount()— подсчитывает количество единиц в двоичном представлении числа. Аналогично работе с битовыми операциями (&,|,^);Objects.equals()— безопасный способ сравнения двух объектов, который обрабатывает null. Если оба объекта равны null, метод вернёт true;Integer.parseInt(),Double.parseDouble()— аналоги операторов приведения типов (например, (int)).
Метод equals() проверяет логическое равенство содержимого объектов. Для строк сравнение учитывает последовательность символов.
Код ITЗагрузка примера кода…
Разбор:
new String("привет")вtext1иtext2создает разные объекты, поэтому==возвращаетfalse.equals(...)уStringсравнивает содержимое, поэтому для одинаковых символов результатtrue.- Для
Integerс небольшими значениями срабатывает кэш оберток, поэтомуnum1 == num2может бытьtrue. - Для более крупных значений (
200) создаются разные объекты, и==снова даетfalse. - Практическое правило: для объектов сравнивайте значение через
equals, а==оставляйте для примитивов и проверки идентичности ссылки.
При создании собственных классов метод equals() следует переопределять вместе с hashCode():
Код ITЗагрузка примера кода…
Разбор:
@Override equals(...)определяет критерий логического равенства по полямnameиage.- Проверка
this == objбыстро обрабатывает случай сравнения объекта с самим собой. - Условие с
getClass()защищает от сравнения объектов разных типов. hashCode()вычисляется из тех же полей, что иequals, чтобы соблюсти контракт коллекцийHashMapиHashSet.- Без согласованной пары
equals/hashCodeравные объекты могут вести себя некорректно в хеш-структурах.
Метод compareTo() возвращает целое число:
- отрицательное;
- если текущий объект меньше аргумента;
- ноль при равенстве;
- положительное при превосходстве.
Код ITЗагрузка примера кода…
Разбор:
compareTo(...)возвращает знак отношения: отрицательное, ноль или положительное значение.- Для строк сравнение лексикографическое и зависит от Unicode-порядка символов.
- Для
Integerметод сравнивает числовые значения без дополнительного преобразования. fruits.sort(String::compareTo)использует методcompareToкак компаратор для сортировки списка.- Такой единый контракт сравнения лежит в основе сортировок и структур вроде
TreeSet.
Методы Math.addExact(), Math.subtractExact(), Math.multiplyExact() контролируют переполнение целочисленных типов.
Код ITЗагрузка примера кода…
Разбор:
max + 1демонстрирует тихое переполнениеint, когда значение циклически переходит в отрицательный диапазон.Math.addExact(...)иMath.multiplyExact(...)проверяют переполнение и выбрасываютArithmeticException.try-catchпозволяет явно отработать аварийный сценарий, а не продолжить с поврежденным результатом.Math.subtractExact(...)делает ту же защиту для вычитания и полезен в финансовой и учетной логике.- Такой подход повышает надежность расчетов, где потеря точности или знак результата критичны.
Метод Integer.bitCount() возвращает количество установленных битов (единиц) в двоичном представлении числа.
Код ITЗагрузка примера кода…
Метод Objects.equals() корректно обрабатывает значения null, избегая NullPointerException.
String s1 = null;
String s2 = null;
String s3 = "текст";
System.out.println(Objects.equals(s1, s2)); // true — оба null
System.out.println(Objects.equals(s1, s3)); // false — null и непустая строка
System.out.println(Objects.equals(s3, s3)); // true — одинаковые строки
// Сравнение без Objects.equals() требует дополнительных проверок
if (s1 != null && s1.equals(s2)) {
// безопасное сравнение без использования Objects.equals()
}
Методы Integer.parseInt() и Double.parseDouble() преобразуют текстовые представления в числовые значения.
Код ITЗагрузка примера кода…
Класс Object
Класс Object — базовый для всех классов в Java. Он определяет поведение, доступное каждому объекту.
Основные методы:
equals(Object obj)— сравнение объектов на логическое равенствоhashCode()— возвращает хеш-код объектаtoString()— строковое представление объектаgetClass()— возвращает объект Class, представляющий тип в рантаймеclone()— создает копию объекта (если поддерживает Cloneable)finalize()— вызывается перед сборкой мусора (устарел и не рекомендуется)wait(),notify(),notifyAll()— методы для межпоточной синхронизации.
Метод equals() определяет логическое равенство объектов. Метод hashCode() генерирует целочисленный хеш-код, используемый в хеш-коллекциях.
Код ITЗагрузка примера кода…
Метод toString() предоставляет текстовое представление объекта. Переопределение улучшает отладку и логирование.
Код ITЗагрузка примера кода…
Метод getClass() возвращает объект класса Class, описывающий тип объекта во время выполнения.
String text = "пример";
Class<?> clazz = text.getClass();
System.out.println(clazz.getName()); // java.lang.String
System.out.println(clazz.getSimpleName()); // String
Integer number = 42;
System.out.println(number.getClass().getName()); // java.lang.Integer
// Проверка типа во время выполнения
Object obj = "текст";
if (obj.getClass() == String.class) {
System.out.println("Это строка");
}
Метод clone() создаёт поверхностную копию объекта. Класс должен реализовывать интерфейс Cloneable.
Код ITЗагрузка примера кода…
Методы синхронизации — wait(), notify(), notifyAll() координируют работу потоков при доступе к общим ресурсам.
Код ITЗагрузка примера кода…
Метод finalize() объявлен устаревшим в Java 9 и удалён в последующих версиях. Для освобождения ресурсов следует использовать интерфейс AutoCloseable и конструкцию try-with-resources.
Условные операторы
★ Условия (условные операторы) управляют потоком выполнения программы, позволяют выполнять разный код, в зависимости от выполнения определённого условия.
if-else
Условный оператор if-else (если/иначе) выбирает путь выполнения программы на основе логического выражения.
int temperature = 22;
if (temperature > 30) {
System.out.println("Жарко");
} else if (temperature > 20) {
System.out.println("Тепло"); // выполняется эта ветка
} else if (temperature > 10) {
System.out.println("Прохладно");
} else {
System.out.println("Холодно");
}
Синтаксис:
if (условие) {
// выполняется, если условие истинно
} else {
// выполняется, если условие ложно
}
Пример:
int age = 18;
if (age >= 18) {
System.out.println("Вы совершеннолетний");
} else {
System.out.println("Вы несовершеннолетний");
}
Особенности синтаксиса:
- Фигурные скобки можно опустить для одиночного оператора, но такой стиль не рекомендуется
- Условие всегда приводится к булевому типу
- Ветки
else ifпроверяются последовательно сверху вниз - Выполняется только первая удовлетворяющая условию ветка
Примеры с логическими операторами:
Код ITЗагрузка примера кода…
Вложенные условия:
int hour = 14;
boolean isHoliday = false;
if (!isHoliday) {
if (hour >= 9 && hour < 18) {
System.out.println("Рабочее время");
} else {
System.out.println("Нерабочее время");
}
} else {
System.out.println("Праздничный день");
}
switch
Оператор switch выбирает одну из нескольких веток выполнения на основе значения выражения.
Синтаксис:
switch (выражение) {
case значение1:
// код
break;
case значение2:
// код
break;
default:
// код по умолчанию
}
Пример:
int day = 3;
switch (day) {
case 1 -> System.out.println("Понедельник");
case 2 -> System.out.println("Вторник");
case 3 -> System.out.println("Среда");
default -> System.out.println("Неизвестный день");
}
Традиционный синтаксис с оператором break:
Код ITЗагрузка примера кода…
Современный синтаксис с оператором -> (доступен с Java 14):
String day = "вторник";
switch (day) {
case "понедельник" -> System.out.println("Начало недели");
case "вторник", "среда", "четверг" -> System.out.println("Середина недели"); // выполняется эта ветка
case "пятница" -> System.out.println("Конец рабочей недели");
case "суббота", "воскресенье" -> System.out.println("Выходные");
default -> System.out.println("Неизвестный день");
}
Оператор switch как выражение (возвращает значение):
int statusCode = 404;
String statusMessage = switch (statusCode) {
case 200 -> "OK";
case 404 -> "Not Found"; // возвращается это значение
case 500 -> "Internal Server Error";
default -> "Unknown Status";
};
System.out.println(statusMessage); // Not Found
Правила использования:
- Выражение в
switchможет иметь типbyte,short,char,int,enum,Stringили их обёртки - Каждая метка
caseдолжна содержать константное выражение - Оператор
breakпредотвращает переход к следующей ветке (проваливание) - Ветка
defaultвыполняется, если ни одна меткаcaseне совпала - В синтаксисе с
->операторbreakне требуется — выполняется только одна ветка
Циклы
★ Циклы позволяют выполнять блок кода несколько раз.
| Конструкция | Порядок | Когда удобна |
|---|---|---|
for | инициализация → проверка → тело → обновление | известно число повторений или нужен индекс |
for (тип x : коллекция) | следующий элемент → тело | безопасный перебор массива, List, Set |
while | проверка условия → тело | число итераций заранее неизвестно |
do…while | тело → проверка условия | минимум один проход (меню, повтор ввода) |
Аналог for…of в JavaScript — цикл for-each (for (int value : values)). Обобщённо — циклы в коде, по JavaScript для сравнения синтаксиса — циклы в JavaScript. Готовые задачи с разбором (FizzBuzz, Fibonacci, пузырёк, линейный поиск) — Lab — консольные задачи на Java.
Интерактивное демо — пошаговый цикл на примере JavaScript (
for,while). В Java синтаксис другой, но порядок шагов тот же. Обобщённо: циклы в коде.
Play ITЗагрузка интерактивного демо…
for
for (для) используется, когда известно количество повторений.
Синтаксис:
for (инициализация; условие; обновление) {
// тело цикла
}
Пример:
for (int i = 0; i < 5; i++) {
System.out.println("i = " + i);
}
Структура содержит три компонента:
- инициализацию;
- условие;
- обновление.
for (int i = 0; i < 5; i++) {
System.out.println("Итерация " + i);
}
// Вывод: Итерация 0, Итерация 1, Итерация 2, Итерация 3, Итерация 4
Инициализация выполняется один раз перед началом цикла. Обычно здесь объявляется и присваивается начальное значение счётчику.
for (int counter = 10; counter > 0; counter--) {
System.out.println(counter);
}
// Обратный отсчёт от 10 до 1
Можно объявить несколько переменных одного типа:
for (int i = 0, j = 10; i < 5; i++, j--) {
System.out.println("i=" + i + ", j=" + j);
}
Условие проверяется перед каждой итерацией. Цикл продолжается, пока условие истинно.
int limit = 3;
for (int i = 0; i < limit; i++) {
System.out.println(i);
}
// Вывод: 0, 1, 2
Бесконечный цикл создаётся опущением условия или указанием константы true:
for (;;) {
// бесконечный цикл
break; // выход по условию внутри тела
}
Обновление выполняется после каждой итерации. Обычно здесь изменяется значение счётчика.
for (int i = 1; i <= 100; i *= 2) {
System.out.println(i);
}
// Вывод: 1, 2, 4, 8, 16, 32, 64
Инкремент i++ увеличивает значение на единицу. Декремент i-- уменьшает на единицу. Можно использовать составные операторы: i += 5, i *= 2.
Каждое выполнение тела цикла называется итерацией. Шаг — изменение счётчика за одну итерацию.
// Шаг равен 3
for (int i = 0; i < 15; i += 3) {
System.out.println(i);
}
// Вывод: 0, 3, 6, 9, 12
// Отрицательный шаг
for (int i = 10; i >= 0; i -= 2) {
System.out.println(i);
}
// Вывод: 10, 8, 6, 4, 2, 0
Цикл for подходит для перебора массивов и коллекций:
int[] numbers = {5, 10, 15, 20};
for (int i = 0; i < numbers.length; i++) {
System.out.println("Элемент " + i + ": " + numbers[i]);
}
String[] words = {"яблоко", "банан", "апельсин"};
for (int i = 0; i < words.length; i++) {
System.out.println((i + 1) + ". " + words[i]);
}
Улучшенный цикл for (for-each) упрощает перебор элементов:
int[] values = {1, 2, 3, 4, 5};
for (int value : values) {
System.out.println(value * value);
}
// Вывод: 1, 4, 9, 16, 25
while
Цикл while повторяет выполнение блока кода, пока логическое условие остаётся истинным. Проверка условия происходит перед каждой итерацией.
Синтаксис:
while (условие) {
// тело цикла
}
Пример:
int i = 0;
while (i < 5) {
System.out.println("i = " + i);
i++;
}
int count = 3;
while (count > 0) {
System.out.println("Осталось: " + count);
count--;
}
// Вывод: Осталось: 3, Осталось: 2, Осталось: 1
Особенности:
- Если условие изначально ложно, тело цикла не выполнится ни разу
- Счётчик или переменная условия должны изменяться внутри тела цикла
- Бесконечный цикл возникает при отсутствии изменения условия
Примеры использования:
Код ITЗагрузка примера кода…
Цикл while удобен, когда количество итераций заранее неизвестно и определяется в процессе выполнения.
do-while
do-while (делать, пока), выполняется хотя бы один раз, даже если условие ложно. Проверка условия происходит после каждой итерации.
Синтаксис:
do {
// тело цикла
} while (условие);
Пример:
int j = 0;
do {
System.out.println("j = " + j);
j++;
} while (j < 5);
int attempts = 0;
do {
System.out.println("Попытка " + (attempts + 1));
attempts++;
} while (attempts < 3);
// Вывод: Попытка 1, Попытка 2, Попытка 3
Сравнение с while:
Код ITЗагрузка примера кода…
Практическое применение — интерактивные меню:
Код ITЗагрузка примера кода…
Цикл do-while применяется, когда требуется как минимум одна итерация независимо от начального состояния условия.
Как выбирать конструкцию на практике
| Задача | Подход |
|---|---|
| Фиксированное число повторений | for |
| Повтор до выполнения условия | while |
| Нужна хотя бы одна итерация | do-while |
| Много веток по одному значению | switch |
| Простой бинарный выбор | if-else |
Сначала пишите вариант, который проще всего читать через месяц.
Для большинства задач это if-else и обычный for, а не "умные" сокращения.
Закрепить циклы на типовых задачах — Lab — консольные задачи.
Следующий шаг с GUI — Lab — Swing (конвертер, список задач).
Типичные ошибки в операторах и циклах
- Сравнение строк через
==вместоequals(). - Пропущенный
breakв классическомswitch. - Условие цикла с
<=вместо<, из-за чего возникает выход за границы массива. - Бесконечный цикл из-за отсутствия изменения счётчика.
- Использование
&вместо&&и|вместо||без понимания разницы.
Связанные статьи
- Типы, boxing/unboxing и сравнение объектов: Типы данных и переменные в Java
- Отладка пошагово (breakpoints, step over): Отладка Java-кода в IDE
- Коллекции и типичные обходы списков: Коллекции в Java