Отладка Java-кода в IDE
Отладка Java-кода в IDE
Отладка (debugging) — способ остановить программу в нужной строке и посмотреть, что реально лежит в переменных, не гадая по println.
Статья ориентирована на IntelliJ IDEA (обзор IDE — IntelliJ IDEA — IDE для разработки на Java; те же приёмы работают в Android Studio). Если вы прошли первую программу в NetBeans — включите отладку кнопкой с жуком; панели Variables и Call Stack называются так же.
| Способ | Когда уместен |
|---|---|
| Отладчик IDE | Логика, циклы, NullPointerException, рекурсия |
println | Быстрая проверка одного значения; в проде не оставляют |
Типовые консольные программы для отладки (циклы, массив, меню) — Lab — консольные задачи. Окна и кнопки (точка останова в обработчике кнопки) — Lab — Java Swing. Полноценные мини-приложения — Простые приложения на Java.
Отладчик говорит с процессом через JDWP — тот же протокол, что и при удалённой отладке сервера без IDE.
Точка останова и запуск
Откройте проект из Первая программа на Java (вариант IDEA или NetBeans) или любой класс с main.
Перед стартом убедитесь, что воспроизводите проблему в одном и том же сценарии. Отладчик полезнее всего тогда, когда поведение стабильно повторяется.
- Откройте файл в редакторе.
- Щёлкните слева от номера строки — появится красная точка (breakpoint).
- Запустите отладку: Shift+F9 в IntelliJ IDEA (или кнопка с жуком).
Пример для пошагового разбора:
Код ITЗагрузка примера кода…
Разбор:
public class DebugExampleобъявляет класс-контейнер, в котором лежит демонстрационный код для отладки.- Метод
main(String[] args)— точка входа: JVM начинает выполнение именно с него. int[] numbers = { ... }создаёт массив целых чисел, аfindMax(numbers)передаёт этот массив в отдельный метод.- Ошибка в цикле
for (int i = 0; i <= array.length; i++)заключается в<=: на последней итерации индекс становится равенarray.length, а это уже выход за допустимые границы0..length-1. - В строке
if (array[i] > max)происходит чтение элемента массива по индексу, и именно здесь при неверной границе цикла отладчик помогает пойматьArrayIndexOutOfBoundsException.
Отладчик остановится на breakpoint и покажет, что цикл выходит за границы массива.
Команды отладчика (IntelliJ IDEA)
| Команда | Клавиша | Действие |
|---|---|---|
| Шаг с заходом | F7 | Выполняет строку, заходит внутрь методов |
| Шаг с обходом | F8 | Выполняет строку, не заходя в методы |
| Шаг с выходом | Shift+F8 | Выходит из текущего метода |
| Продолжить | F9 | До следующей точки останова |
| Остановить | Ctrl+F2 | Завершить сеанс отладки |
На первых шагах достаточно уверенно владеть тремя действиями: F8 (шаг с обходом), F7 (шаг с заходом) и F9 (продолжить). Остальные команды подключаются по мере роста задач.
Панели отладчика
- Variables — значения локальных переменных и полей объектов.
- Frames (Call Stack) — цепочка вызовов методов от
mainдо текущей строки. - Breakpoints — список всех точек останова; можно задать условие (например,
i > 5).
Условная точка останова
Полезна в циклах, когда нужно остановиться только при определённом значении:
public class ConditionalBreakpoint {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println("Итерация: " + i); // условие: i > 5
}
}
}
Разбор:
- Цикл
for (int i = 0; i < 10; i++)выполняет 10 итераций и печатает текущее значение счётчикаi. System.out.println("Итерация: " + i)формирует строку и выводит её в консоль на каждом шаге.- Ключевая идея примера — условный breakpoint на этой строке: IDE останавливает выполнение только когда условие (например,
i > 5) становится истинным. - Такой подход экономит время при отладке длинных циклов: вы смотрите только интересующие итерации, а не проходите все вручную.
В IntelliJ IDEA: правый клик на breakpoint → More → поле Condition.
Пример — отладка алгоритма
Код ITЗагрузка примера кода…
Разбор:
- Метод
findSecondMax(int[] array)проходит массив один раз и параллельно поддерживает два значения:maxиsecondMax. Integer.MIN_VALUEиспользуется как безопасное начальное значение для второго максимума, чтобы любой реальный элемент массива мог его заменить.- Ветвь
if (array[i] > max)обновляет оба значения: старый максимум уходит вsecondMax, новый элемент становитсяmax. - Ветвь
else if (array[i] > secondMax)срабатывает, когда элемент не стал максимумом, но подходит на роль второго по величине. - Такой разбор удобен в отладчике: в
Variablesвидно, как параmax/secondMaxменяется на каждой итерации.
Задание: поставьте breakpoint на первой строке цикла и проследите, как меняются max и secondMax на каждой итерации.
Пример — отладка рекурсии
Код ITЗагрузка примера кода…
Разбор:
- Метод
factorial(int n)реализован рекурсивно: он вызывает сам себя с аргументомn - 1, пока не дойдёт до базового случая. - Условие
if (n <= 1) return 1;— базовый случай рекурсии, который завершает цепочку вызовов и предотвращает бесконечный спуск. - Выражение
return n * factorial(n - 1);накапливает произведение при обратном выходе из рекурсии. - Для
n = 5фактическая цепочка вызовов выглядит как5 * 4 * 3 * 2 * 1, а вFramesэто видно как стек вложенных вызовов. - Этот пример хорошо показывает, зачем в отладке нужна панель Call Stack: она раскрывает текущую глубину рекурсии и порядок возврата значений.
В панели Frames видно вложенные вызовы factorial(5) → factorial(4) → … → factorial(1).
Удалённая отладка (JVM)
Для приложений без IDE можно включить JDWP:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
Разбор:
-agentlib:jdwp=...подключает агент отладки JDWP к процессу JVM.transport=dt_socketуказывает сетевой транспорт через сокет.server=yозначает, что JVM сама открывает порт и ждёт подключения IDE.suspend=nпозволяет приложению стартовать сразу, без паузы до подключения отладчика.address=*:5005открывает порт5005на всех интерфейсах; в прод-среде это настраивают осторожно и обычно ограничивают доступ.
IDE подключается к порту 5005 и работает так же, как с локальным процессом. Подробнее — в "Справочнике по Java".
В цикле ниже ошибка границы: сумма 1..10 должна быть 55, а не 66. Найдите её через отладчик (F8 по итерациям) и исправьте условие цикла.
public class DebugQuiz {
public static void main(String[] args) {
int sum = 0;
for (int i = 0; i <= 10; i++) {
sum += i;
}
System.out.println("Сумма 1..10: " + sum);
}
}
Разбор:
- Переменная
sumнакапливает сумму значений счётчикаiв циклеfor. - Диапазон
i = 0; i <= 10включает 11 значений (от 0 до 10), поэтому результатом становится 55 для1..10только если стартовать сi = 1. - В текущем коде формулировка и диапазон расходятся: программа считает
0..10, а подпись говорит1..10. - Отладчик помогает увидеть это по шагам: в каждой итерации видно текущие
iиsum, поэтому ошибка границы становится очевидной. - Практический фикс — изменить начало цикла на
i = 1(или скорректировать текст вывода под фактический диапазон).
Практическая схема отладки
Когда ловите баг в реальном проекте, удобно идти по шаблону:
- Воспроизвести ошибку стабильным сценарием.
- Поставить breakpoint ближе к месту неверного результата.
- Проверить входные данные и состояние объекта.
- Пройти ветвления
F8/F7и найти расхождение ожидания с фактом. - После фикса запустить тот же сценарий повторно.
Так отладка перестаёт быть "угадайкой" и становится повторяемым процессом.
Что проверять в первую очередь
nullв полях и аргументах.- Границы массивов и коллекций (
<против<=). - Правильность условий в
ifиswitch. - Состояние объекта после вызова метода, а не только до.
Связанные статьи
- Условия, циклы и частые логические ошибки: Операторы и циклы в Java
- Типы, boxing/unboxing и сравнение: Типы данных и переменные в Java
- Потоки и поведение JVM в runtime: JVM, память и потоки