Перейти к основному содержимому

Отладка 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.

Связь с JVM

Отладчик говорит с процессом через JDWP — тот же протокол, что и при удалённой отладке сервера без IDE.


Точка останова и запуск

Откройте проект из Первая программа на Java (вариант IDEA или NetBeans) или любой класс с main.

Перед стартом убедитесь, что воспроизводите проблему в одном и том же сценарии. Отладчик полезнее всего тогда, когда поведение стабильно повторяется.

  1. Откройте файл в редакторе.
  2. Щёлкните слева от номера строки — появится красная точка (breakpoint).
  3. Запустите отладку: 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 (или скорректировать текст вывода под фактический диапазон).

Практическая схема отладки

Когда ловите баг в реальном проекте, удобно идти по шаблону:

  1. Воспроизвести ошибку стабильным сценарием.
  2. Поставить breakpoint ближе к месту неверного результата.
  3. Проверить входные данные и состояние объекта.
  4. Пройти ветвления F8/F7 и найти расхождение ожидания с фактом.
  5. После фикса запустить тот же сценарий повторно.

Так отладка перестаёт быть "угадайкой" и становится повторяемым процессом.


Что проверять в первую очередь

  • null в полях и аргументах.
  • Границы массивов и коллекций (< против <=).
  • Правильность условий в if и switch.
  • Состояние объекта после вызова метода, а не только до.

Связанные статьи