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

Приемы отладки IntelliJ

· 5 мин. чтения

1. Обзор

В этом руководстве мы рассмотрим некоторые расширенные средства отладки IntelliJ .

Предполагается, что основы отладки уже известны (как начать отладку, действия Step Into , Step Over и т. д.). Если нет, пожалуйста, обратитесь к этой статье для получения более подробной информации об этом.

2. Умный шаг

Бывают ситуации, когда в одной строке исходного кода вызывается несколько методов, например doJob(getArg1(), getArg2()) . Если мы вызываем Step Into action (F7), отладчик переходит к методам в порядке, используемом JVM для оценки: getArg1getArg2doJob .

Однако мы можем захотеть пропустить все промежуточные вызовы и перейти непосредственно к целевому методу . Smart Step In action позволяет это сделать.

По умолчанию он привязан к Shift + F7 и при вызове выглядит так:

./cab03d02a20c0b32a0db3f578c6ebaf8.png

Теперь мы можем выбрать целевой метод для продолжения. Также обратите внимание, что IntelliJ всегда помещает самый внешний метод в начало списка. Это означает, что мы можем быстро перейти к нему, нажав Shift + F7 | Введите .

3. Перетащите кадр

Мы можем понять, что некоторая интересующая нас обработка уже произошла (например, вычисление текущего аргумента метода). В этом случае можно удалить текущие кадры стека JVM, чтобы повторно обработать их.

Рассмотрим следующую ситуацию:

./cbc9244e5343101bb5449e6456f37f01.png

Предположим, нас интересует отладка обработки getArg1 , поэтому мы отбрасываем текущий кадр ( метод doJob ):

./a796c721b9cd207387215cc77a50c8a7.png

Теперь мы находимся в предыдущем методе :

./ee3f6a6d33be0d811334e7e60e9c63b0.png

Однако на этом этапе аргументы вызова уже рассчитаны, поэтому нам также нужно отбросить текущий кадр :

./3def357502afaf82f30c9caa9a4ed556.png

Теперь мы можем повторно запустить обработку, вызвав Step Into .

4. Полевые контрольные точки

Иногда не приватные поля изменяются другими классами не через сеттеры, а напрямую (это в случае со сторонними библиотеками, где мы не контролируем исходный код).

В таких ситуациях может быть трудно понять, когда модификация выполнена. IntelliJ позволяет создавать точки останова на уровне полей, чтобы отслеживать это.

Устанавливаются как обычно — кликаем левой кнопкой мыши по левой канавке редактора на строке поля. После этого можно открыть свойства точки останова (щелкнуть правой кнопкой мыши по метке точки останова) и настроить, если нас интересуют чтение поля, запись или и то, и другое :

./739ce5c76c999264bc1d4528e3be83d5.png

5. Регистрация точек останова

Иногда мы знаем, что в приложении есть состояние гонки, но не знаем, где именно оно находится. Это может быть проблемой, особенно при работе с новым кодом.

Мы можем добавить операторы отладки в исходники нашей программы. Однако для сторонних библиотек такой возможности нет.

Здесь может помочь IDE — она позволяет устанавливать точки останова, которые не блокируют выполнение после попадания, а вместо этого создают операторы регистрации .

Рассмотрим следующий пример:

public static void main(String[] args) {
ThreadLocalRandom random = ThreadLocalRandom.current();
int count = 0;
for (int i = 0; i < 5; i++) {
if (isInterested(random.nextInt(10))) {
count++;
}
}
System.out.printf("Found %d interested values%n", count);
}

private static boolean isInterested(int i) {
return i % 2 == 0;
}

Предположим, мы заинтересованы в регистрации фактических параметров вызова isInterested .

Давайте создадим неблокирующую точку останова в целевом методе ( Shift + щелчок левой кнопкой мыши по левой полосе редактора). После этого давайте откроем его свойства (щелкните правой кнопкой мыши точку останова) и определим целевое выражение для логирования :

./00822eae0f4ca027efb9fbc47639b3e3.png

При запуске приложения (обратите внимание, что по-прежнему необходимо использовать режим отладки) мы увидим вывод:

isInterested(1)
isInterested(4)
isInterested(3)
isInterested(1)
isInterested(6)
Found 2 interested values

6. Условные точки останова

У нас может возникнуть ситуация, когда конкретный метод вызывается из нескольких потоков одновременно, и нам нужно отлаживать обработку только для определенного аргумента.

IntelliJ позволяет создавать точки останова, которые приостанавливают выполнение только в том случае, если выполняется определенное пользователем условие .

Вот пример, который использует исходный код выше:

./50ffad9310b7ed1f01907dad8025e04e.png

Теперь отладчик остановится на точке останова, только если заданный аргумент больше 3.

7. Знаки объекта

Это самая мощная и наименее известная функция IntelliJ. По сути, это довольно просто — мы можем прикреплять собственные метки к объектам JVM .

Давайте посмотрим на приложение, которое мы будем использовать для их демонстрации:

public class Test {

public static void main(String[] args) {
Collection<Task> tasks = Arrays.asList(new Task(), new Task());
tasks.forEach(task -> new Thread(task).start());
}

private static void mayBeAdd(Collection<Integer> holder) {
int i = ThreadLocalRandom.current().nextInt(10);
if (i % 3 == 0) {
holder.add(i);
}
}

private static class Task implements Runnable {

private final Collection<Integer> holder = new ArrayList<>();

@Override
public void run() {
for (int i = 0; i < 20; i++) {
mayBeAdd(holder);
}
}
}
}

7.1. Создание меток

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

Выберите его, нажмите F11 ( действие Mark Object ) и укажите имя цели:

./794912333d2d633b6ba8067e1a76cca9.png

7.2. Просмотр меток

Теперь мы можем видеть наши пользовательские метки объектов даже в других частях приложения:

./76e44ef3d58686b7cfab80ec4dc63b87.png

Круто то, что даже если помеченный объект недоступен из фреймов стека в данный момент, мы все равно можем увидеть его состояние — открыть диалог Evaluate Expression или добавить новые часы и начать вводить имя пометки.

IntelliJ предлагает дополнить его суффиксом _DebugLabel :

./87cede8440a98115f603b05cc08ce384.png

Когда мы оцениваем его, отображается состояние целевого объекта:

./3f6a30c81e5d6e2b6fde500720e046aa.png

7.3. Метки как условия

Также возможно использовать метки в условиях точки останова:

./a626f9a8c87ec8aa7b265044bd02dcd8.png

8. Заключение

Мы проверили ряд приемов, значительно повышающих производительность при отладке многопоточного приложения.

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