Точки останова: что это такое и почему они такие мощные
4 января 2023 г.Это была трудная неделя. В настоящее время я просматриваю окончательный вариант моей будущей книги по отладке. Это всегда отрезвляющий и волнующий момент. Момент, когда все месяцы работы вдруг становятся «настоящими».
Я также записал 9 видеороликов для YouTube, в результате чего общее количество видеороликов в курсе достигло 29 (еще больше на подходе). Я запускаю два дополнительных бесплатных курса, один предназначен для начинающих.
Еще одна посвящена современному программированию на Java, которую я выпущу очень скоро. Оба варианта будут бесплатными на моем канале YouTube (обязательно "Нравится, подпишитесь и поделитесь").
В статье этой недели мы поговорим о точках останова. Это длинно, поскольку то, что мы имеем в виду, когда говорим о точке останова, на самом деле просто «точка останова строки». Как вы можете видеть ниже, их гораздо больше.
www.youtube.com/watch?v=eXRqKqSp7x0
Расшифровка
Добро пожаловать в четвертую часть отладки в Scale, где мы надираем задницы и присваиваем имена. Имена переменных!
В этом разделе мы обсудим точки останова, которые являются основными единицами работы при отладке. Но в них гораздо больше, чем просто поломка.
Мы говорили о самых основных точках останова в нашей первой части. На этот раз мы углубимся в некоторые менее известные нюансы.
Условные точки останова
Начнем с условных точек останова. Условные точки останова позволяют нам определить условие для попадания в точку останова. Это предотвращает постоянную остановку потока в точке останова. Я обсуждал это ранее с объектом маркера myThread, который мы создали в предыдущем видео.
В этом случае мы останавливаемся только в том случае, если он отличается от текущего потока. Это означает, что эта точка останова сработает только в том случае, если ее вызовет другой поток. Это отличный способ обнаружить проблемы, связанные с потоками, такие как взаимоблокировки или гонки. Эту функцию стоит повторить, поскольку она очень важна.
Точки останова метода
Точки останова метода довольно проблематичны.
Напомним, что мы можем поместить точку останова на любую строку в методе, и точка останова там остановится. Это настолько распространено, что мы просто называем это «точкой останова».
Мы можем переключить стандартную точку останова строки с помощью Control-F8 или, альтернативно, на Mac с помощью Command-F8
.
Точки останова метода останавливаются, когда мы вводим метод. Вы можете подумать, что это бесполезно. Почему бы не использовать точку разрыва строки?
Вы будете правы. Точки останова метода намного медленнее, и вам не следует их использовать: для этого... Однако есть вариант использования точек останова метода.
Обратите внимание, что поскольку точки останова метода очень медленные, они обычно эмулируются средой IDE. Он просто использует точки останова строки для имитации точек останова метода. Для нас, пользователей IDE, это почти незаметно, но нам нужно знать об этом, потому что в прошлом это было не так.
Вы все еще можете найти сообщения от пользователей на StackOverflow, жалующихся на медлительность точек останова методов.
Чтобы увидеть пример использования точек останова метода, давайте перейдем в окно управления точками останова. Допустим, мы хотим разбить все методы, начинающиеся с букв I и S в классах, имя которых начинается с Prime.
Мы можем сделать это, используя подобное выражение, чтобы остановить все такие методы на основе шаблона. Это может показаться надуманным, но на самом деле очень полезно, если у вас есть абстрактный базовый класс, подклассы которого следуют соглашению об именах и имеют много связанных методов.
Вы хотите отслеживать все, и вы можете сделать это, используя этот подход. Обратите внимание, что вы также можете использовать здесь точки трассировки и получить очень глубокое ведение журнала. Через несколько минут мы обсудим точки трассировки.
Полевые точки наблюдения
Полевые контрольные точки — это не обычные точки останова. Точка наблюдения будет останавливаться каждый раз, когда значение поля изменяется или каждый раз, когда оно читается. Это замечательный способ отследить случай, когда какой-то код изменяет переменную или выясняет, как значение поля распространяется в коде.
Обратите внимание, что мы можем настроить, будет ли он останавливаться на операциях чтения, записи или на обоих, используя этот диалог. Мы также можем сделать точку наблюдения условной, как и любую другую точку останова.
Это называется точкой наблюдения, а не точкой останова, потому что это не та точка, где код останавливается. Он останавливается в точке доступа, а не на самом поле.
Управление точками останова
IDE предоставляют пользовательский интерфейс для управления всеми контрольными точками. Мы можем управлять уже имеющимися точками останова и создавать новые точки останова в меню просмотра точек останова. Я могу открыть его с помощью параметра меню просмотра точек останова или использовать комбинацию клавиш Shift-Control-F8
.
Обратите внимание, что на Mac нам нужно использовать команду вместо управляющей клавиши.
В этом диалоговом окне мы можем отключать, удалять и редактировать точки останова. Вы заметите, что у нас есть много вариантов, которые мы скоро обсудим. Отсюда мы можем добавить точки останова. Есть несколько интересных вариантов, но сейчас я просто добавлю точку останова в простом поле.
Точки останова исключений — это отстой (или нет?)
Мы можем установить точку останова для остановки при возникновении исключения. Но это небольшая проблема. У меня есть два варианта. Во-первых, я могу поймать конкретное исключение по имени. Это полезно, если вы заранее знаете, какое исключение будет сгенерировано.
Но я не могу вспомнить многих случаев, когда это происходило, и я еще не знал строку, где выбрасывается исключение.
Более ценный вариант использования — отлов всех исключений. Причина, по которой это полезно, заключается в том, что иногда я могу не смотреть на консоль во время отладки. Исключения могут быть зарегистрированы там, и я могу полностью их пропустить.
Я могу перезапустить сеанс отладки и пропустить эти исключения. Но если точка останова внезапно останавливается на исключении, это сложно не заметить. Проблема в том, что перехват всех исключений по умолчанию не работает!
К сожалению, это трудно показать в простом основном приложении, поэтому я переключил демонстрацию на простое приложение с весенней загрузкой. Содержание заявки в данном случае не имеет значения. Давайте включим перехват любого исключения и посмотрим, что произойдет…
После включения улова я пытаюсь продолжить, но он снова и снова снова и снова попадает в точку останова. Код опрашивает WebService в фоновом режиме. В этой веб-службе отсутствует заголовок HTTP, поэтому код, анализирующий этот заголовок, завершается с ошибкой NumberFormatException.
Мы застряли на коде, который выдает это исключение, которое является действительным, поскольку Java не предоставила другого способа анализа числовых заголовков, когда этот код был написан.
Так что мы можем сделать? Это эффективно делает остановку при любом исключении бесполезной практически для любого реального приложения.
Давайте немного переместим окно, а затем увеличим масштаб, чтобы увидеть, что мы здесь делаем.
Теперь мы можем определить фильтр класса. Обратите внимание, что я добавляю к обоим фильтрам префикс минус, чтобы превратить это в фильтр исключения. Здесь я определяю фильтр для всех пакетов Java и всех пакетов Sun. Это означает, что каждое исключение, которое обрабатывается в этих пакетах, не будет нарушено.
Как только я нажимаю «ОК», я могу нажать «Продолжить», и приложение запускается без прерывания проблемных исключений. Другие исключения будут работать как обычно и дадут нам знать, когда что-то сломается в нашем коде!
Удивительно, что это не стандартная среда IDE. Без него функция практически бесполезна.
Точки трассировки (точки журнала)
Точки трассировки или LogPoints — одни из самых важных типов точек останова, которые у нас есть. Мы можем добавить точку трассировки, щелкнув желоб с нажатой клавишей Shift. Это открывает знакомый диалог точки останова, но выглядит немного по-другому. Во-первых, обратите внимание на это:
Опция приостановки не отмечена; обратите внимание, что мы можем преобразовать любую точку останова в точку трассировки, сняв флажок приостановки. По умолчанию точка останова прерывается. Он останавливает текущий поток и приостанавливает его, чтобы мы могли не спеша проверить стек приложения и посмотреть, что происходит.
Точка трассировки не приостанавливает текущий поток. Приложение достигает точки останова и продолжает работать без остановки. Это довольно новаторски, как вы переступите?
Ну, вы не знаете. Вместо этого мы можем сделать несколько других вещей…
Мы можем регистрировать слова «столкновение с точкой останова» всякий раз, когда мы сталкиваемся с точкой останова, но это не так полезно, если у нас нет только одной точки трассировки и мы хотим знать только, достигли ли мы этой точки. Мы можем печатать трассировку стека каждый раз, когда достигаем точки трассировки, что действительно более полезно. Но ненамного.
Трудно читать много следов в списке и следовать им. Я хочу сосредоточиться на другом.
Обратите внимание, что в оценке и журнале уже было значение cnt
, потому что я выбрал значение cnt
в среде IDE перед нажатием клавиши Shift в поле.
Мы можем написать любое выражение, которое хотим напечатать здесь. Я могу вызвать метод для записи описательных строк и т. д. Это буквально стандартный оператор журнала, который я могу динамически добавлять в код. Обратите внимание, что я все еще могу сделать эту точку трассировки условной, как и любую условную точку останова.
Это означает, что я могу напечатать любое значение в данный момент времени. Как и любой регистратор. Это впечатляющая особенность. Представьте себе точки останова методов, которые мы обсуждали ранее с этими точками трассировки; мы можем мгновенно регистрировать в масштабе. Нажимаем ОК.
А затем запустите эту программу; мы можем видеть, что журнал, который мы добавили в точку трассировки, выводится на консоль, как если бы мы написали его в коде!
Группировка и наименование
Группирование и присвоение имен имеют решающее значение, когда мы масштабируем нашу отладку.
Мы можем назвать точку останова, используя описание, чтобы указать ее семантическое значение. Это очень полезно, когда мы работаем со многими точками останова. Мы также можем сгруппировать их по файлам, пакетам и т. д.
Но здорово то, что мы можем создавать собственные группы для точек останова и отключать точки останова в группе одним переключателем. Это очень удобно!'
Это избавляет нас от утомительного нажатия кнопки «Продолжить» при попытке достичь состояния и позволяет нам управлять множеством точек останова.
Но истинная ценность здесь в масштабе. Допустим, у вас сложный сеанс отладки с несколькими одновременно работающими точками трассировки.
Вы можете сгруппировать сеанс и отключить точки останова при переключении на другую ветку для отладки чего-то еще. Затем вернитесь туда, где вы были, когда закончите.
Отключить точку останова
Иногда точка останова срабатывает постоянно, и нам нужен только определенный стек.
Мы можем отключить точку останова до тех пор, пока не сработает другая точка останова или исключение, после чего точка останова автоматически включится. Это избавляет нас от необходимости постоянно нажимать «Продолжить», если мы хотим протестировать только определенный путь.
Это также работает с исключениями и точками останова исключений, и мы можем принять решение о поведении после. Мы хотим отключить его снова или продолжить как обычно?
Это очень полезно в случае сбоя, который происходит только по определенному пути. Я могу добавить точку трассировки к первому методу. Затем отключите фактическую точку останова, которую я хочу в этой точке трассировки.
Фильтры экземпляров
Фильтры экземпляров позволяют принимать точку останова только от определенного экземпляра объекта.
Обратите внимание на экземпляр текущего объекта, отмеченный как «этот» в часах. Обратите внимание, что за символом at следует число 656.
Это идентификатор объекта Java, эквивалентный указателю в других языках программирования. В фильтрах экземпляров мы можем ограничить точку останова, чтобы она срабатывала только для определенного объекта.
Скажем, эта точка останова на линии часто попадает в несколько экземпляров, но меня интересуют только результаты конкретного экземпляра объекта и я хочу отфильтровать весь шум. Я могу открыть диалоговое окно с дополнительными сведениями, нажав здесь.
Мне нужно проверить параметр фильтра экземпляра, а затем ввести идентификатор объекта экземпляра, который я хочу отфильтровать. Это будет означать, что точка останова не остановится для других типов экземпляров. Чтобы применить это изменение, я нажимаю "Готово".
На данный момент мы видим, что фильтр экземпляра все еще останавливается в ожидаемой точке останова…
Поэтому следующим шагом будет изменение фильтра экземпляров на другой экземпляр объекта. Я придумываю число, так как это просто для теста.
Обратите внимание, что когда я щелкаю правой кнопкой мыши точку останова, я получаю настроенную версию этого диалогового окна, потому что у нас есть фильтр экземпляров. Это действительно полезная функция, которая значительно упрощает работу с пользовательским интерфейсом.
Теперь, когда мы внесли это изменение, точка останова больше не прерывается.
Фильтры классов
Фильтры классов не имеют смысла для типичной точки останова строки. Фильтры классов имеют смысл при использовании точки наблюдения поля или точки останова исключения.
В этом случае у меня есть публичное поле. Я фильтрую доступ к полю, чтобы игнорировать любой доступ из основного основного класса. Если к полю обращается другой класс, сработает точка останова.
Это очень полезно, иначе я могу получить много попаданий в точку наблюдения от текущего класса. Но я хочу увидеть и другие случаи.
Фильтры вызывающих абонентов
Фильтр вызывающего объекта реализует фильтр на основе сигнатуры вызывающего метода. Чтобы использовать его, нам снова нужно перейти в расширенное меню. Он поддерживает подстановочные знаки, поэтому я могу ограничить вызывающую сторону, чтобы разрешить только метод запуска.
Обратите внимание, что он использует нотацию JVM для подписи метода, что является довольно сложной темой, о которой я расскажу позже. У меня есть соответствующий раздел в моей книге по отладке.
Метод продолжает останавливаться в точке останова, как и ожидалось, потому что, как мы видим здесь, метод run действительно находится в трассировке стека. Таким образом, фильтр применяется правильно и достигает точки останова.
Мы снова можем настроить точку останова в пользовательском интерфейсе быстрого редактирования фильтра. В этом случае я изменил фильтр, чтобы найти несуществующий метод stop, и действительно, точка останова больше не прерывается.
Заключительное слово
Это длинное видео. Надеюсь, вы нашли его поучительным и понятным. В следующем видео мы поговорим об отладке потоков и коллекций.
Если у вас есть какие-либо вопросы, пожалуйста, используйте раздел комментариев. Спасибо!
Оригинал