Отладчик

В

этой главе будут рассмотрены различные стратегии отладки. Большая ее часть будет посвящена отладчику, доступному в среде JBuilder. Существуют и другие, менее сложные с технической точки зрения, но, тем не менее, мощные стратегии отладки, о которых вы, как разработчик, забывать не должны.

Темы, подробно проанализированные в этой главе, включают:

■ Пошаговое выполнение кода.

■ Установка в программе точек прерывания, условных точек прерывания и то­чек прерывания, выводящих состояние переменных.

■ Просмотр значений переменных.

■ Отладка потоков.

■ Использование стека вызовов для определения функций, вызвавших функ­цию, во время останова выполнения программы в точке останова.

■ Вывод данных на стандартное устройство вывода.

■ Использование классов протоколирования из состава JDK версии 1.4.0 и выше.

■ Отключение отладки для отдельных классов

■ Просмотр загруженных классов и статических данных в программе во время выполнения.

Отладчик JBuilder является одним из основных элементов интегрированной сре­ды разработки. Разработчики используют его практически каждый день и, как пра­вило, не один раз. Понимание принципа работы и умение работать с отладчиком — это ключевые составляющие умения работать со средой JBuilder.

"Крутые" парни не пользуются отладчиками

Есть люди, которые считают, что отладчики придуманы для неопытных про­граммистов или являются одним из видов самообмана. Не так уж много можно при­вести подобных утверждений, которые были бы настолько далеки от истины. Давай­те рассмотрим каждое из утверждений по отдельности.

■ Отладчики придуманы для неопытных программистов Когда я работал в компа­нии Borland, то сталкивался с очень и очень многими программистами, и будьте уверены, практически все из них пользуются отладчиками. Разница между хорошим и отличным программистом заключается не в том, что пер-

Вый пользуется отладчиком, а второй нет. Как раз наоборот, разница заклю­чается как раз в том, что отличный программист великолепно знает, как пользоваться отладчиком, в то время как хороший или посредственный про­граммист обладает меньшими навыками работы с отладчиком.

■ Отладчики являются одной из форм самообмана. Можно с уверенностью ска­зать, что когда люди начали использовать лошадей и повозки, лучшие бегуны в племени огульно оговаривали эту новую "технологию". Ведь, в конце кон­цов, быстрая лошадь всегда быстрее самого быстрого бегуна. Таким образом, бегуны были на грани потери своей значимости и советовали людям не пользоваться лошадьми. То же происходило, когда были изобретены автома­тические ткацкие станки, паровозы и автомобили, или когда люди создали калькулятор, текстовый процессор и, конечно же, отладчик. Умение выпол­нять отладку программы без отладчика — это, конечно, искусство, достойное восхищения. Но восхищения заслуживают и быстрые бегуны и люди, которые могут в уме выполнять сложные математические вычисления. Тем не менее, большинство из нас для быстрого передвижения пользуются велосипедом или автомобилем, а математические вычисления выполняют с помощью калькулятора или компьютера. Следуя этой простой логике, для отладки при­ложения мы будем пользоваться отладчиками.

Я уверен, что отладчик JBuilder является одним из самых мощных и полезных средств всей среды JBuilder. Настойчивое и серьезное изучение отладчика JBuilder представляет собой одно из немногих занятий, которые позволяют быстрее достичь успехов в программировании на языке Java. Он помогает писать лучший код за меньшее время. Что вам еще нужно?

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

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

■ Использование методов System, out. println И System, err. print In.

■ Запись в файлы журналов.

■ Использование утверждений.

Все это достаточно старые стратегии, но последние две получили новую жизнь и были добавлены в язык Java версии 1.4.0.

Запись в стандартное устройство вывода

При отправке сообщений в метод System. out. println они, как правило, на­правляются на стандартное устройство вывода. Таким образом, эта стратегия отлад­ки аналогична использованию оператора WriteLn в языке программирования Pascal или оператора printf в С/С++.

При использовании вывода сообщений на стандартное устройство вывода в каче­стве средства отладки часто бывает удобно в начале класса объявить статическую бу­леву переменную:

Private final static boolean debug = true;

Далее эта переменная может использоваться для определения того, должны ли выводиться отладочные сообщения:

If (DEBUG)

{

System, out. pr in tin ("Значение DataDetails В MyClass: ,* + dataDetails) ;

}

B приведенном примере переменная DataDetails Может быть любой перемен­ной, содержимое которой вы хотите определить. Она может быть возвращаемым значением функции, строкой или переменной другого типа, которая может помочь выявить ошибки в программе. Если в программе нет локальных переменных, на ос­новании которых можно определить причину ошибки или состояние программы, эту часть кода можно просто пропустить:

If (DEBUG)

{

System.Out.Println("Возникла ошибка");

примечание)

Поскольку переменная DEBUG объявлена как окончательная и стати­ческая, большинство Java-компиляторов будут действовать очень разумно при оптимиза­ции кода, если в начале кода значение переменной DEBUG установлено равным false. Для всех практических целей, если значение переменной DEBUG установлено равным false, код, помещенный в блок вывода отладочного сообщения, будет полностью игно­рироваться компилятором, и не будет влиять на размер окончательной программы. Ус­тановите значение переменной DEBUG равным true, и код блока выдачи отладочного сообщения снова войдет в состав программы. Описанный метод, наверное, не так эф­фективен, как использование условной компиляции в языках Object Pascal или С/С++, тем не менее, все они близки по духу. Если вы хотите больше узнать об этом методе, прочтите спецификацию языка Java (Java Language Specification), пункт 14.20, ,’Невыполня­емые операторы" (Unreachable Statements). На момент написания книги упомянутая спецификация была доступна по адресу Http://java. sun. com/docs/books/jls/ Second edition∕html∕statements.Doc. html.

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

Public static final String IntToStrPadO(int value, int paddings)

{

String rawString ≈ String. valueθf(value);

StringBuffer paddedString = new StringBuffer(rawString); while (paddedString. length() < paddings)

{

PaddedString. insert(O, ‘ O, ) ;

}

Re turn paddedS tring. toString();

}

Эта функция, если вы помните, предназначена для преобразования целочислен­ных значений в строки и дополнения строки начальными нулями. Например, в ка­честве аргументов функции можно передать значения 7 и 3 и получить идентифика­ционный номер Джеймса Бонда: 007. При передаче значений 3 и 4 Функция вернет 0003 (возможно, это тоже идентификационный номер какого-то агента?).

Если в приведенную функцию ввести оператор System. out. printin, можно по­лучить достаточно хорошее представление о том, что происходит внутри функции. Например, предположим, что функция изменена следующим образом:

Public static final String IntToStrFadO(int value, int paddings)

{

String rawString ≈ String. valueθf(value);

StringBuffer paddedString = new StringBuffer(rawstring); while (paddedString. length() < paddings)

{

PaddedString. insert(Oz , O,) ; if (DEBUG)

{

System. out. printin("Вызов: " + paddedString);

)

)

Return paddedString. toString();

)

Если значение переменной debug установлено равным true и функция вызыва­ется с аргументами 25 и 8, в командной строке можно будет увидеть следующие ре-

Зультаты:

Вызов:

025

Вызов:

0025

Вызов:

00025

Вызов:

000025

Вызов:

0000025

Вызов:

00000025

По непонятным причинам многие разработчики не любят программистов, кото­рые выводят данные на стандартное устройство вывода, пользуясь этим способом как методом отладки. Можно предположить, что это вызвано тем, что такой метод считается устаревшим. Тем не менее, несложно заметить, что целый ряд великолеп­ных программистов с многолетним опытом работы очень активно пользуются выво­дом данных на стандартное устройство вывода. Таким образом, применяйте этот ме­тод, если в вашем случае он эффективен, и не принимайте во внимание мнение дру­гих разработчиков, считающих его устаревшим.

Кроме того, иногда удобно объявить функцию, через которую передаются все со­общения об ошибках:

If (DEBUG)

{

ReportError(this, : π + errorDetails);

)

После ЭТОГО МОЖНО Объявить функцию reportError, которая будет указывать имя класса, передающего сообщение об ошибке, время, когда ошибка произошла, и, возможно, другую полезную информацию. Функция reportError может выво­дить данные на стандартное устройство вывода или записывать их в файл.

Если при выполнении программы с целью отладки вы хотите передавать самому себе сообщения, используйте метод System. out. printin. При необходимости вы-

Вода сообщений об ошибках, пользуйтесь методом System. err. println. Как пра­вило, текст, выводимый методом Systern. err. prɪntln, отличается цветом (напри­мер, выводится красным цветом). Это позволяет среди стандартных отладочных со­общений быстро обнаружить сообщения об ошибках.

Очевидно, что метод System, out. pr in tin можно интенсивно применять и в приложениях с графическими интерфейсами пользователя. При этом графический интерфейс ведет себя нормально, но панель сообщений среды JBuilder заполняется данными, которые вы выводите на стандартное устройство вывода. После проведе­ния отладки при подготовке окончательного варианта программы установите значе­ние переменной debug равным false, и сообщения в панель сообщений JBuilder выводиться не будут.

Запись в файлы журналов

Начиная с версии 1.4.0, в язык Java ввели встроенные средства записи сообще­ний в файлы журналов. Эти новые классы протоколирования могут использовался в качестве великолепных средств отслеживания событий в программе. Программа TestLogger, находящаяся в каталоге utilities среди сопровождающих книгу мате­риалов, может служить примером использования такой стратегии отладки.

В начале файла класса поместите следующий оператор import: import java. util. logging.*;

Кроме того, в объекте необходимо объявить поле, в котором будет храниться эк­земпляр класса Logger:

Logger log;

После этого в одном из методов программы файл журнала можно открыть с по­мощью переменной Logger, которая была объявлена как глобальный класс:

Logger log;

Private String getHomeDir()

{

String homeDir = System. getProperty("user. home") +

System. getProperty ("file. separator") + ,’elvenware" ; com. elvenware. codebox. FileBox. ConfirmDir(homeDir);

System. err. println(,’homeDir: ,, + homeDir);

Return homeDir + System. getProperty("file. separator");

}

Void jButtonl_actionPerformed(ActionEvent e)

{

Try

{

Handler fh = new FileHandler(getHomeDir() + "elvenware. log"); Logger. getLogger("com. elvenware").addHandler(fh); log = Logger. getLogger("com. elvenware"); log. SetLevel(Level. ALL);

1

Catch (java. io. IOException ioe)

{

System. err.ρrintln(ioe);

)

Log. fine("samn);

Log. log(Level. WARNING r "Tim");

JButtonl. setText("Записано в: " + getHomeDir ()) ;

}

Метод GetHomeDir Определяет домашний каталог пользователя и создает в нем подкаталог Elvenware. Подпрограмма ConfirmDir Из набора утилит codebox прове­ряет наличие каталога. Если каталог отсутствует, он будет создан:

Public static final boolean ConfirmDir(String aPath)

{

Boolean result = true;

File appDir = new File (aPath) ; if(appDir. exists() )

{

If ( !appDir. IsDirectory())

{

System. out. println("Имя " + APath + " Не является каталогом."); Result ≈ false;

}

} else if(!appDir. mkdir()) ,

{

System. out. println("Каталог " + aPath + " Создать невозможно."); Result = false;

}

Return result;

}

После создания домашнего каталога, в котором хранится файл журнала, следую­щий шаг заключается в открытии файла:

Handler fh = new FileHandler(getHomeDir() + "elvenware. log");

Класс FiieHandier входит в состав новых средств протоколирования. Он расши­ряет абстрактный класс Handler. Класс FiieHandler Можно использовать для вы­полнения записи в файл или в несколько файлов, изменяя дескриптор файла, когда его размер достигает определенного значения.

Затем созданный экземпляр класса FiieHandier Передается средствам протоко­лирования JDK для регистрации дескриптора:

Logger. getLogger("testlogger”).addHandler(fh);

Как результат, вы получаете возможность извлечь экземпляр инструмента прото­колирования, который позволяет записать данные:

Log = Logger. getLogger("testlogger");

Имя, передаваемое в качестве аргумента, должно быть основано на пакете или классе, выводящем данные. При желании можно использовать имена с разделитель­ной точкой, например, "testlogger. Framel".

Уровни протоколирования

Перед записью сообщений в файл журнала можно установить уровни сообще­ний, которые будут регистрироваться:

Log. SetLevel(Level-ALL);

Если вы просмотрите исходный код Java, то увидите, что класс Level является псевдоперечислимым типом, аналогичным рассмотренным в других частях книги, например, в главе 16.

Доступны следующие уровни протоколирования сообщений:

Severe (наибольшее значение)

WARNING

INFO

CONFIG

FINE

FINER

Finest (наименьшее значение)

All — протоколировать все сообщения об ошибках

Off — отключить протоколирование сообщений об ошибках

Ниже приведены два способа протоколирования сообщений для определенного уровня:

Log. fine("Очень детализированная информация о программе ");

Log. log(Level. WARNING, "Возможно, что-то идет не так, как ожидалось");

Результат выполнения приведенного кода в каталоге home∕elvenware выглядит следующим образом:

<7xml verβion="1.0" encoding= "windows-1252" standalone="no"7>

<!DOCTYPE log SYSTEM "logger. dtd">

<log>

<record>

<date>2003-05-10T17:06:30<∕date>

<milliβ>1021075590984<∕milliβ>

<sequence>O</seguence>

<logger>com. elvenware<∕logger>

<level>FINE<∕level>

<clasu>testlogger. Framel<∕class> <method>jButtonl_actionPerformed</method>

<thread>l0<∕thread>

<message>sam<∕message>

<∕record>

<record>

<date>2003-05-10T17;06:31<∕date>

<nilliβ>1021075591000<∕milliβ>

<sequencβ>l</sequence>

<logger>com. elvenware<∕logger>

<level>WARNING<∕level>

<claβa>testlogger. Framel<∕claβ8> <method>jButtonl_actionPerformed</method>

<tħread>10<∕thread>

<mesβage>Tim<∕message>

<∕record>

Если посмотреть в середину двух больших XML-дескрипторов, содержащихся в приведенном коде, можно обратить внимание, что в одном из них уровень протоко­лирования ошибок установлен равным fine, а во втором — warning. Если уровень

Протоколирования установить равным warning, первое из двух приведенных сооб­щений записываться не будет:

Handler fh = new FileHandlerfgetHomeDirO + "elvenware. log");

Logger. getLogger("com. elvenware").addHandler(fh); log = Logger. getLogger(»com. elvenware") ; log. setLevel(Level. WARNING);

Если уровень протоколирования установить равным severe, ни одно из сообще­ний выводиться не будет. В таком случае файл журнала будет выглядеть следующим образом:

<?xml version="1.О" Encoding="windows-1252" standalone="no"7>

<!DOCTYPE log SYSTEM "logger. dtd,,>

<log>

<∕log>

Несложно понять, как задействовать рассмотренную методику для создания от­ладочных отчетов. За счет простого изменения уровня протоколирования сообще­ний можно протестировать код на предмет наличия серьезных ошибок и получить самые общие отчеты о состоянии программы.

В этом разделе мы только поверхностно коснулись возможностей средств прото­колирования. Так, например, существуют средства, предназначенные для считыва­ния файлов журналов и генерации HTML-отчетов, основанных на их содержимом. Средства протоколирования дают пользователям возможность включать запись в журналы регистрации и отсылать разработчику программы отчеты.

Конечно, некоторые разработчики посчитают технологию протоколирования несколько устаревшей. Тем не менее, создание файлов журналов может сэкономить время при разработке сложных проектов. Они часто позволяют обнаружить ошибки еще задолго до того, как пользователи начнут подозревать о существовании оши­бок.

Утверждения

Утверждения (assertions) применяются в среде JBuilder при использовании вер­сии JDK 1.3.1, поставляемой вместе с JBuilder, и в версии JDK 1.4.0 и выше. В языке Java утверждения появились только начиная с JDK 1.4.0, но среда JBuilder предос­тавляла функциональные возможности утверждений уже для версии JDK 1.3.1. При­веденные ниже примеры можно найти в сопровождающих книгу материалах, в ката­логе AssertTest.

Утверждения предназначены для тестирования булевых функций для подтверж­дения того, что возвращается значение true. Например, ниже приведена самая простая проверка, подтверждающая, что вы живете на Земле, а не на какой-то дру­гой планете:

Void jButtonl_actionPerformed(ActionEvent Е)

{

Int i = 2 + 2; Assert i == 4;

Если приведенное утверждение не дает в результате true, что-то в вашей про­грамме работает неправильно. Например, может быть, вы живете на планете, на ко­торой 2 + 2 дает 5. Для большинства людей это будет плохой новостью.

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

Void jButton2_actionPerformed (ActionEvent Е)

{

String paddedɪnteger = IntToStrPadO(4, 3); assert (paddedɪnteger. equals (‘, 004 ")) ;

)

Эта функция позволяет очень легко проверить, правильно ли работает метод intτostrPadθ, который мы рассматривали ранее. Если метод возвращает не 004, в нем содержится ошибка, и утверждение вызовет исключение.

В JBuilder с JDK 1.3.1 использование утверждений можно включить, выбрав в меню Project ∣ Project Properties и перейдя на страницу General. В верхней части страницы находится опция Enable the assert keyword (Разрешить ключевое слово assert). Установите флажок возле этой опции. Утверждения будут вызывать исклю чение Java.ɪang. error.

примечаниеПри использовании JDK 1.4.0 в версии JBuilder 7 вам не нужно устанавливать опцию Enable the assert keyword. Для того чтобы использовать утверждения, выбе­рите в меню Project ∣ Project Properties, перейдите на страницу Run, щелкните на кнопке Edit для текущей конфигурации времени выполнения и выберите значение -enabieassertions В качестве параметра, передаваемого виртуальной машине Java. B этом случае утверждения вызывают исключение Java. Iang. AssertionError. В Любом случае вы имеете возможность щелкнуть на выделенном синим цветом име­ни файла в панели сообщений и перейти на источник ошибки.

Если вы знакомы с популярным проектом JUnitf То наверняка обратите внимание на аналогию между JUnit И применением утверждений. Однако, по сравне­Нию с утверждениями, JUnit Обеспечивает более глубокую поддержку.

Утверждения обладают гораздо большим потенциалом, нежели было указано в этом коротком введении. Более подробное описание принципа использования ут­верждений для отладки приложений можно найти на Web-странице по адресу Http://java. sun.Сот/J2se∕l.4/docs/guide/lang/assert. html.

В версии JDK 1.4.0 и выше утверждения можно отключить простым удалением ключа -enabieassertions В диалоговом окне Project Properties. Для дальнейшего расширения возможностей можно воспользоваться условной компиляцией, кото­рая рассматривалась выше в этой главе в отношении переменной debug.

Отладчик JBuiIder

Основное назначение этой главы заключается, конечно, не в изучении стандарт­ного устройства вывода или средств протоколирования. Тема главы — отладчик JBuilder. Нет необходимости лишний раз говорить о том, что одним из ключевых преимуществ отладчика является то, что он не требует изменения кода. Все описан­ные до сих пор методы требовали ручного введения в код дополнительных строк.

599

Отладчик JBuilder — чрезвычайно мощный инструмент. Ему даже можно посвя­тить отдельную книгу, но существует несколько основных фактов, которые должен знать каждый разработчик, и эти факты будут рассмотрены на нескольких следую­щих страницах.

Включение отладчика

В соответствии с указаниями, приведенными в главе 3, создайте новое приложе­ние. Назовите его SimpleDebug.

В редакторе выделите Framel и прейдите в режим конструирования. Поместите в окно кнопку. Создайте для кнопки обработчик события и вставьте в него следую­щий код:

Void jButtonl_actionPerformed (ActionEvent Е)

String message = "Мое сообщение";

System. err. println(message);

}

Это вся программа, с которой мы будет работать. Вас можно понять, если вы со­чтете ее слишком простой, тем не менее, она позволяет изучить все то, о чем мы будем говорить ниже. Фактически при исследовании приведенной программы с помощью от­ладчика в ней можно обнаружить практически неограниченный уровень сложности.

Для запуска отладчика установите точку останова на операторе System. err. println. Для установки точки останова перейдите в режим редактиро­вания кода и щелкните левой кнопкой мыши на поле слева от оператора Println. Кроме того, для установки и снятия точки останова можно воспользоваться клавишей F5. Рядом с кодом должна появиться красная отметка, как показано на рис. 29.1. На приведенном рисунке поле находится непосредственно слева от оператора Println И непосредственно под символом X для закладки файла исходного кода Framel.

я
file edit search view project run team wbards tools window help
,∣bui(der 7 - 5.∣,srcjava∕jbbook∕debug∕simpledebug∕src∕iirr(ptedebug∕f,o & йh ⅜ β 0 "≠ ■ *> ш ⅛ × '& ’ ’ i & ` 1 ♦
1⅛ ⅛j ɪl £3 simpledeoubjpx -
,mjconttrmdir,33 simpledebugjpx ⅛ sjt «project source* ffi ⅞t simpledebug,*⅛4> pntrnel ∣ >,sold jbuttonl-acclonperfor>ed(Λccιoniwenc e)
{
i string bessage » "this ɪs »y message"; >■
sjstea.etɪ.printin(bessage)j
,, ri,, 'metlav⅛
source ldoslgntiboani uwll⅛tj⅞¾Γ
рис. 29.1. для создания точки останова щелкните на поле слева от оператора println при помощи клавиши f5 можно создавать и удалять точки останова
1 simpledebug.html
⅛ © imports j
⅛ if framel
¾ jframe i ⅛ frameio
pκres⅞wnd,ιwevent(wir'<row f β<*r,nt .actionperrormed{ac∣,
¾j j g:\jb7\jdkl.3.1∖bln∖javao -classpath "g:\srcjeva\jbbook\debug\si»pledebug\clas3es;c±. i-xrunjdsp: transport-dt_socket,address-rohan: 1273,suspend∙y slbpledebug.slbpledebug

'w⅛Γ""

… S

600

Теперь, когда точка останова установлена, в меню JBuilder выберите Run ∣ Debug Project (Запуск | Отладить проект). Кроме того, отладчик можно запустить с помо­щью комбинации клавиш Shift+F9. Еще один способ запуска отладчика заключает­ся в нажатии кнопки с зеленой стрелкой на фоне белого квадрата, которая находит­ся правее кнопки с зеленой стрелкой, используемой для запуска программы. Если всех перечисленных способов недостаточно, можно выполнить щелчок правой кнопкой мыши на исходном коде главного файла приложения в панели проекта и в появившемся контекстном меню выбрать Debug using "SimpIeDebug" (Отладка с ис­пользованием "SimpIeDebug").

примечаниеОднако при запуске отладчик начинает загрузку приложения аналогично тому, как приложение загружается при нормальном запуске. В запущенном приложении щелкните на созданной вами кнопке. Приложение перестанет реагировать на ваши действия, как в случае зависания. Это происходит потому, что выполнение прило­жения достигло точки останова, установленной на операторе println. Если перей­ти в интегрированную среду разработки, вы увидите экран, показанный на рис. 29.2.

Отладчик использует достаточно большой объем памяти. Если вы обна­ружите, что отладчик работает медленно или не отвечает на ваши действия, возможно, придется увеличить объем ОЗУ. 256 Мб — это хороший объем ОЗУ для машины, на кото­рой осуществляется разработка приложений в среде JBuiIder. На моей машине установ­Лено 512 Мб и отладчик JBuiIder Работает просто великолепно.

Если вы еще не сталкивались с видом, показанным на рис. 29.2, то почувствуете себя истинным первооткрывателем.

Установленная точка останова привела к остановке выполнения программы. Это позволяет заглянуть в глубины программы.

рис. 29.2. отладчик jbuilder находится в панели сообщений, возле редактора и панели структуры

ishowcurrentframe

DisplaycurrantthreadlS call stack

Пока что не пытайтесь выполнять программу в пошаговом режиме и не застав­ляйте выполнять отладчик никаких действий. Посвятите несколько минут на изу­чение того, что видите на экране.

Оказывается, на экране присутствует достаточно большой объем информации. Начнем с того, что рассмотрим, каким образом отладчик может предоставить "мгновенный снимок" с точки зрения выполнения определенной строки кода про­граммы. После этого мы научимся пользоваться средствами управления отладчика и, наконец, рассмотрим различные виды программы, доступные в отладчике.

Основы отладчика

В нижней части рисунка 29.2 находится строка текста, которая говорит о том, что выполнение программы приостановлено на точке останова, находящейся в строке 66 класса siɪnpiedebug. Framel. Слева от этой строки расположено несколь­ко пиктограмм. Щелкните на самой правой пиктограмме. Указатель мыши на рис. 29.2 как раз находится на этой пиктограмме, и вы видите всплывающую подсказку для кнопки.

Только что вы щелкнули на кнопке Show Current Frame (Показать текущий фрейм). (Это вид по умолчанию для отладчика, поэтому при первом щелчке на этой кнопке ничего не произойдет.) В терминах интегрированной среды разработки этот вид отображает стек вызовов текущего потока. Другими словами, кнопка Show Current Frame позволяет перейти к виду, который дает возможность исследовать те­кущее состояние программы. Точнее, справа в окне она предоставляет переменные, доступные в настоящий момент времени. В левой части окна отладчика находится список методов, вызванных до выполнения метода, в котором установлена точка ос­танова. Этот вид известен как Стек вызовов {call stack). Методы, вызванные ранее, записываются в стек, где вы их можете просмотреть. При выборе метода в стеке вы­зовов, отладчик переходит к этому выбранному методу.

Тем не менее, пока что обратите внимание на три переменных, которые находят­ся в правой части отладчика. Самая верхняя из них носит название This. Она со­держит ссылку на текущий экземпляр класса Framei. Вторая переменная, ActionEvent, Это переменная, переданная методу, в котором установлена точка останова. Третья переменная представляет собой объявленную вами строку Message. Как видно на рисунке 29.2, она содержит текст "This is my message" ("Мое сообщение").

На рис. 29.3 окно отладчика увеличено и теперь оно занимает практически все пространство интегрированной среды разработки. Слева находится длинный пере­чень методов, которые были вызваны до остановки выполнения программы на точке останова. Если посмотреть в самый низ списка, можно увидеть метод, который за­пустил просматриваемый поток.

На правой части рис. 29.3 можно видеть, что я выполнил щелчок на пиктограм­ме со знаком плюс, которая находится непосредственно возле строки message. Это позволяет просмотреть содержимое этого объекта. Внутри объекта можно увидеть, что перемена Count Содержит значение 18. Это количество символов в строке. Ниже приводятся все 18 символов, составляющие массив значений типа Char.

602

Если внимательно посмотреть на рис. 29.3, можно обратить внимание на нерас­крытый знак плюс возле второй строки данных об объекте Message. Если щелкнуть на нем, на экране появится информация, представленная на рис. 29.4.

На рис. 29.4 видно, что слева возле большинства элементов находятся пиктог­раммы. Круглые пиктограммы обозначают классы, пиктограмма в верхней строке соответствует объекту, а пиктограмма возле строки java. io. Serializable обозначает ин­терфейс. Пиктограммы, которые находятся примерно на одну треть от нижнего края окна возле слов count, hash и offset, обозначают базовые типы. Возле слова CtbConverter находится затененная версия пиктограммы из верхней части окна, которая обозначает нулевой объект. В справочной системе JBuilder можно найти полный пере­чень пиктограмм, используемых в интегрированной среде разработки JBuilder.

К этому времени у вас должно сложиться твердое мнение о том, что отладчик JBuilder — это очень мощный инструмент. Его мощь заключается в том, что он пре­доставляет настолько большой объем информации о программе, который вы даже

Jautlder 7 [§] ⅛ ZCrc Ja∙√flZ^faBook7Pe⅛Uft∕S¾rnplePehu⅛∕? <∕sjmpledebug∕frame∙ 1. J*⅛ » X

P if К⅛i>¾♦ ‘∖’

⅞ > -~¾,*⅜⅜>j⅛[**]∙∕⅝⅛⅛Fs ..: ɛr √* l⅛-√‘4. ■ ¾L⅛

FtLif It I& JPββwi)i⅛ijhι ∙<j *;&ЛИЙс®и<и>1 *φβ,i⅛Hw∙bwn⅛⅛l .*⅛frtm∙ij

4 IctonPtrtorcnedO — M1 Mmpitrtebug. MflreActionPartOnmdO i450.∣rmβs⅛ я ScbonPettormtdO. ISOflJarafciwins ‘■

* AreAetlonPertbffnadO 378. Iarajcswti

I StlPraaaadO 250. Javaxewtnfl Da<ιι § InouaaRataaaadO — 21 BJrrexrMng a ProceasMouaaEranlC.3715Javaaw IproeeasErantO 3344. Jara araCom∣

J ProcasaErantO 1164. jara. aiM. Conh »0 IlItaaIchEranifnplO 2393Jrre. ara(

I OtepatchEranimplO 121 3. Jeraerac

5 SJltpatchEranlO 2487. IavaawtCorn S IMargMMouaaErafltO 2451jara, awt I ProeessMouaaErafltC: 221 BJara aw и OiepatchEranio 2123. JaraasMUgI* HdiapatchErantlmptO 1200, Jrre. ага (

§ dιapatchErarttmp∣O: 814.jara. rM. W JdlapatchErantO 2487Jara araCom~

Я OJtpatchEranIO ЗЗд JaraaraEranbii? 5 PwnpOnaErarflForHererchK °13tl J:

• 5* P JT ⅛ 6 4 ¾⅛,sm⅝w⅛ι∣ugΓ

Я ħwħ wɪ о В ofi∙t Inlr О R *18 WhH ChMlI" Chidt 8]

!йга-т SB Pl-W : ssra-r Sra-*∙

= Bw— Mra-V I «га-*- Sm— Mra-W ; Bra-V Wpd∙∙∙

Spii-W Wpii-V Вря-v BPfj-V SSpd-V

Spd-V

Bpij-V

⅛4rara* .___________________________

Ffla £<М S∙arcħ Jflaw Project Run Team Vnjards Iooia Window H∙∣p

О (f d ’ ⅜ Ж ∙ <⅛⅛-⅜

*-*4i∙ .Z, .. … <i.……

Ft U «3 3 jPβt^∙*w*⅛Λ> i * A*βmcβufo<∣i IrjkeMrtMfWtfflvnf *⅛⅛⅛*∙**tj

^l⅜wnl^l⅛¾¾iCl⅛raf ¾f……………………… -i’-~⅞- ∙

flto ξdrt s∙∙ιch view project gun tefro wjardt tooh fflflndow ΓwΦ,й ⅜ message iaralang1btingrathis ianwmeaaagf - ф ■ о iarajyg-btrtng рис. 29.3. увеличенный вид i отладчика, на котором слева
находится стек вызова методов, а справа — объект string
j >г b⅜y>lt>w⅜ι⅛l bwnfumtl docl hittorl
i pumpewnteforherarciwo ■ 88jara i pixnpewfllao 63. jara ага eraniois i itfflo. 83, iaw. iraeranmtaemchthaah
mk∣ ~ г. ' ∙ , .. ∙jbbook «vug/ mpiβ, buj'∙. -' — ptedebu⅛∕fr

; 98 manageJamJangSfcing* Thla la mym∙taβgr, fe ∙ ∣rre. Cang.8Mng

HjaratongObjact MfaraIoSartttftabto И jaw Iang-ComparaMa ⅜ McCsnrartar few IangThraadLocai ■ nuN

¾ CASEJNSENSTrNE-OROER Jrreutt CMnparator ■ (java tong.8MngBCaaMnaanaibraComparator<834c} ft? ⅜ Jrretong-SMngtCasMnaanrtIwCMnparetor

• JrretongObjact H Jrreutt-Comparator

S

Jrre to Strtaiftabta

MttabtarakmUlO: Isnga BS7S7H60B833Q2832β Я8 MbCiSflrartar Jrre tong ThreadLoetts nun

рис. 29.4. вывод даже большего, чем вы могли ожидать, объема информации об экземпляре класса string, который используется в методе
octionperformed

ж-
⅜s⅝⅛⅝⅛f

Il MrtaFaretatrflFiaIda ∣ara. to. ObjβctSbaamfto∣<t∣β Iarato-ObjacBlreamFItIdJOl ⅛ SertttVeretaNUP long« >8049784470754687710

Не в силах обработать. Фактически панель в левой части рис. 29.3 отображает только один из потоков, которые вы имеете возможность исследовать в отладчике.

Тем не менее, эта глава не будет подробно рассматривать все сложные возможно­сти отладчика. Наша задача на данном этапе заключается не в изучении всевозмож­ных инструментов отладчика, а в исследовании методов применения полученной информации. Каким образом найти тот важный фрагмент информации, который поможет решить часто встречающиеся при отладке проблемы?

Наилучший метод — научиться управлять потоком событий в отладчике. В сле­дующем разделе будет приведено общее описание видов, предоставляемых отладчи­ком для исследования состояния программы.

Управление отладчиком

На рис. 29.5 показан внешний вид пиктограмм, используемых для управления ходом событий в отладчике. Эти пиктограммы расположены в нижней части отлад­чика левее пиктограмм, показанных на рис. 29.2.

Слева находится квадратная кнопка, которая предназначена для остановки рабо­ты и выхода из программы. Следующая кнопка с зеленой стрелкой позволяет про­должить выполнение программы после остановки на точке останова. Для перезапус­ка программы после ее остановки на точке останова не пользуйтесь зелеными кноп­ками в панели инструментов интегрированной среды разработки JBuilder. Они приведут к запуску второй копии вашей программы. Вместо них воспользуйтесь кнопкой с зеленой стрелкой, которая продолжает выполнение программы после ее останова. Третья кнопка на рис. 29.5 позволяет остановить выполнение программы в любой момент времени без использования точки останова. Как показано на рис. 29.5, она затенена. Это вызвано тем, что программа уже остановлена на точке останова, по­этому нет смысла останавливать выполнение программы, если она уже остановлена.

Следующие четыре кнопки позволяют выполнять программу в пошаговом режи­ме. При пошаговом выполнении вы имеете возможность проходить программу по одной строке за раз и проверять ее состояние после каждой строки.

Хочу еще раз повторить. Отладчик позволят выполнять программу в пошаговом режиме и исследовать состояние переменных программы после выполнения каждой строки кода. Это свойство является, пожалуй, самым мощным инструментом отлад­ки, используемым изо дня в день.

Во всех новых фильмах, подобных "Матрице" или "Человеку-пауку", зрители оха­ют и ахают, когда ход событий на экране замедляется, чтобы показать, каким обра­зом их видит герой фильма. При замедлении событий герой может уклоняться от ударов, брошенных в него предметов и даже летящих в него пуль. Смысл заключает­ся не в том, что реакция героя настолько высока, а в том, что он может замедлять время и избегать попадания нацеленных в него пуль. В одном из захватывающих моментов фильма "Человек-паук" Питер Паркер в момент уклонения от удара смот­рит на людей вокруг него. Для него время течет настолько медленно, что он не толь­ко успевает уклониться от удара, но и осматриваться вокруг.

Рис. 29.5. Пиктограммы, используемые

Для управления потоком событий в Ц ð* ɑ* 1, Ф ∙* ,R Coo

Программе

Отладчик позволяет вам делать, по сути, то же самое. При пошаговом выполне­нии программы события замедляются, и вы имеете возможность отследить все, что происходит в программе. Отладчик наделяет вас воистину сверхъестественными способностями. Теперь, вы, возможно, начинаете понимать, почему не все хотят, чтобы вы пользовались отладчиком. Отладчик делает вас слишком сильным и отни­мает преимущество, которые имеют другие по сравнению с вами. Как иногда гово­рят в фильмах, отладчик уравнивает шансы всех.

примечаниеВ отладчике имеется четыре кнопки, которые дают возможность выполнять про­грамму в пошаговом режиме. Первая кнопка позволяет включать и выключать ре­жим, который называется Интеллектуальным пошаговым выполнением (Smart Step). Интеллектуальное пошаговое выполнение программы предотвращает вас от входа в код JDK или Borland, который не является частью вашей программы и, стало быть, отладки не требует. При выключенном режиме интеллектуального пошагового вы­полнения вы имеете возможность заходить в код этих классов. В большинстве слу­чаев рекомендуется работать при включенном режиме интеллектуального пошаго­вого выполнения.

В редакциях SE И Enterprise Можно получить полный контроль над тем, какие классы включены, а какие отключены для режима интеллектуального пошагового выполнения программы. Для этого используется нижняя пиктограмма в левой части от­ладчика (см. рис. 29.8). Ниже в этой главе будет рассмотрено, как работают инструмен­Ты отладчика, связанные с этой кнопкой.

Две следующих кнопки позволяют входить в метод или переходить (т. е. "пере­скакивать") через него. На рис. 29.6 я воспользовался кнопкой перехода через метод (горячая клавиша F8) для перехода через метод, в котором находится точка основа, и достижения места непосредственно возле фигурной скобки в конце метода. Если на­жать клавишу F8 еще раз, управление передается методу, вызвавшему данный метод.

рис. 29.6. переход через строку кода в отладчике для достижения конца метода
actionperformed

Последняя, третья из рассматриваемых кнопка, обеспечивает выход из метода. Она предназначена как раз для выхода из выполняемого метода и перехода в вызы­вающий метод (см. рис. 29.7).

рис. 29.7. переход через другую строку кода для входа в метод, вызывающий actionperformed,к сожалению, оба метода, показанных на рис. 29.6 и 29.7, содержат слово actionperformed. тем не менее, если внимательно на них посмотреть, можно заметить, что это два различных метода. в частности, второй метод является частью объекта адаптер, в то время как первый — это метод jbutton1_actionperformed кнопки.
примечание

Выход из метода реализуется кнопкой быстрого выхода, подобно рычагу ката­пульты в самолете. Она, как правило, используется при необходимости выхода из текущего и перехода к следующему методу.

Будем надеяться, что вы получили полное представление об отладке программы в режиме пошагового выполнения. Мы еще некоторое время продолжим об этом го­ворить, однако быстро работу в пошаговом режим можно изучить только на основе практики.

Три последних кнопки в нижней части отладчика позволяют вставить точку остано­ва, добавить слежение за переменной и перейти к текущей точке выполнения. Выше в этой главе мы уже говорили о последней кнопке из числа упомянутых. Точки останова также уже рассматривались. О слежении за переменной мы поговорим чуть ниже.

Виды отладчика

На данный момент было рассмотрено все, за исключением одной пиктограммы в нижней части отладчика. Второй важный набор пиктограмм находится в левой час­ти окна. Каждая пиктограмма в левой части отладчика соответствует определенному виду, в котором отладчик может представить проект. Внешний вид пиктограмм по­казан на рис. 29.8.

примечаниеРасположение пиктограмм можно менять, как видно на рис. 29.8. Это можно считать дополнительной возможно­стью. При необходимости восстановления исходного порядка пик­тограмм выполните щелчок правой кнопкой мыши на отладчике и выберите в контекстном меню пункт Restore default view order (Восстановить порядок видов по умолчанию).

Вид Сообщений (Message View)

Верхняя пиктограмма открывает командную строку, которую JBuiIder использовал для запуска программы, а также выходные данные программы. Этот вид представлен на рис. 29.7. В нижней части рисунка видны результаты работы программы, передавае­мые на стандартное устройство вывода сообщений об ошибках.

рис.29.8.
пиктограммы, которые позволяют переключаться между различными видами отладчика
Ниже находится пиктограмма вида потоков. Более точно, она открывает вид потоков (Threads View), стеков вызовов (Call Stacks View) и данных (Data View). Этот вид был рассмотрен выше в этой главе, когда мы изучали состояние программы при остановке ее выполнения на точке останова. В нем можно изу­чить текущее состояние переменных, например, строковые сооб­щения, и стек вызовов методов, полученный на момент останова на точке останова.

r add watchрис. 29.9. установка слежения за переменной е метода action performed, которая передается в этот обработчик прерывания: actionperformed(actionevent е)Вод Слежения за переменными (Watch View)

Ниже находится пиктограмма вида слеже­ния за переменными. Слежение за переменны­ми было одним из самых важных частей отлад­чика. В современных отладчиках, например, в JBuiIder, они не имеют такого значения, по­скольку состояние большинства переменных можно просмотреть в виде потоков.

При необходимости добавления в окно сле­жения новой переменной щелкните правой кнопкой мыши на имени переменной. На экра­не появится длинное контекстное меню, В его нижней части находится опция, позволяющая добавлять в окно слежения новые переменные

И выражения. При выборе этой опции на экране появляется диалоговое окно уста­новки слежения Add Watch, показанное на рис. 29.9. На рис. 29.9 определяется зна­чение переменой Е Метода BctlonPerformed: actionPerformed(ActionEvent Е).

примечаниеКроме того, добавить переменную в окно слежения можно с помощью пиктограммы, показанной на рис. 29.5. Эта пиктограмма — вторая справа, и она же един­ственная пиктограмма, которая не была рассмотрена в предыдущем разделе. Я реко­мендую не пользоваться ею, а щелкнуть правой кнопкой мыши на имени переменной и в контекстном меню выбрать опцию добавления переменной в окно слежения. Преиму­щество этого метода заключается в том, что переменная будет автоматически внесена в диалоговое окно слежения, показанное на рис. 29.9. В любом случае описание переме­Ной придется вводить вручную.

После закрытия диалогового окна Add Watch значение выбранной переменной можно просматривать в отладчике. В контекстном меню окна слежения за перемен­ными, которые вызывается по щелчку правой кнопкой мыши на окне, присутствуют дополнительные опции, позволяющие, например, создать плавающее окно, содер­жащее текущий вид отладчика.

На рис. 29.10 обратите внимание на то, что вы имеете возможность видеть пере­менную ActionCommand, соответствующую событию ActionEvent, Исследуемому в данный момент. Переменная ActionCommand содержит значение "jButton1". Это по­лезная информация, поскольку она позволяет определить элемент управления, выз­вавший обработчик события. Другими словами, в приведенном примере метод был вызван в результате щелчка пользователем на кнопке jButtonl.

Мы уже говорили, что разница между отличным и хорошим программистами заключается в том, что один использует отладчик, а второй — нет. Все программис­ты должны пользоваться отладчиком, но программист начинающего уровня не все­гда может понять, что означают данные actionCommand, представленные на рис. 29.10. Более опытный программист понимает, что приведенная информация позво­ляет определить компонент, который вызвал метод ActionPβrformed. Вы не долж­ны смущаться при использовании отладчика, более того, для углубленного понима­ния отладчика и выводимой им информации необходимо как можно больше рабо­тать с ним.

Вид точек останова (Breakpoint View)

Под пиктограммой окна слежения за переменными в левой части отладчика на­ходится пиктограмма, которая позволяет просмотреть все установленные точки ос­танова (см. рис. 29.11). Если в виде точек останова щелкнуть правой кнопкой мыши на точке останова, установленной в строке 66, на экране появится диалоговое окно, показанное на рис. 29.12.

рис. 29.10. исследование в отладчике отслеживаемой переменной. в данном случае вы просматриваете переменную е типа actionevent, которая была передана методу octionperformed

примечаниеВид на рис. 29.11 показывает, что в коде программы в строке 66 установлена одна точка останова. Поскольку точка останова только одна, содержимое вида может по­казаться практически бесполезным, но если в программе их 10 или 20, этот вид мо­жет сыграть немаловажную роль.

Одновременное использование 10 Или 20 Точек останова — это не та­кая уж невероятная ситуация. Фактически подобное случается достаточно часто. Иногда один и тот же разработчик несет ответственность за разные части одной и той же про­граммы. Это может вызывать проблемы, поскольку разработчик может иметь один на­бор точек останова для отладки одной части программы и второй набор — для отладки другой ее части. Очень раздражает ситуация, когда выполнение программы останавли­вается на точках останова в той части программы, для которой вы в данный момент не хотите производить отладку. Одна из хитростен при работе с точками останова состоит в том, чтобы для проекта создать несколько JPX-файпов. В одном файле можно устано­вить точки останова для одного конкретного вида программы, например, той ее части, ко­торая работает с Internet-трафиком. Этот файл будет использоваться для отладки именно этой части программы. В другом JPX-файле описывается другой набор точек останова, которые позволяют проводить отладку кода, относящегося к интерфейсу пользователя, который обрабатывает данные, поступающие от пользователей. Новый JPX-файл для про­екта можно создать с помощью меню JBuiIder, Выбрав пункт File ∣ New ∣ Project ∣ Project For Existing Code (Файл Новый | Проект | Проект для существующего кода).

jbu'der7-5 5rc javazjbbookzdebufcziimpifcdebu ⅛c.∙s∣mp edebugzfram⅛τ java,iflle edit search view project run team wtards tools window help
d ∙⅞i'⅜ ∙ x h*⅛⅜i-⅛⅛-⅛fc»■
$ - >* ∣φ
ft № it sl s3 slmpteoe *
3p simpledebuglpx = ⅛∙ ⅛9∣ «project source’
: & <fc slmpledebui
a~"^
,x ⅛. fraroet ∣
fcaael adaptee;
,...,i simpiedebug html . a slmoiedehuojaya ..,Γramel-jdutxonl-accιonλdaj3ter (fcaael adapt ее) (
tmi∙.adaptee » adaptee;
,ρvbllc void actionpercorbed(actιonivent e),fremerjav.,о θrβakpσint pnspffnff,> borderlayoutl,souttafoeelgnl baanj uhi-i doc; hlstoy},actions r*⅛τ÷⅛τκ r stoptocecutlon Γ^ uogmessaga,г 'bιl'z⅛sjkf.f⅛sgtj7
рис. 29.11. вид точек останова программы позволяет узнать, что в строке 66 проекта simpledebug была определена точка останова
<jii impoits
э frame1
% jframe
⅛ frameio ,
processwιndσwevenl(wι ibuttoni ^acttonperformo
s
j⅛ ...
class simpledebug framei; line 66 __ —∙i∙ j
 
∣a 
x~ 
а й* h i'⅛ ⅞⅞ ^¾i.<t⅝a⅜
jd kstmptepebugf
llnebreakpolnt,f∙ i⅞ss вате! jsimpiedebugframei г filename.
une number: в

cancelhelpРис. 29.12.Диалоговое окно Breakpoint Properties (Свойства точки останова)

Точки останова, которые не останавливают выполнение программы

О Breakpoint Properties

A< *. . . * J> f-.-. г-:-.-..S..-..⅛- :-‘ ∙√∙,∙ .ʌ√∙<> ∙’∙ ∙ √ ~-

> Ll∏β mφ∂lφθl ftl" λ*’

*f ⅛⅞SS name] Jsinit Edebug. Frame1

…. .^ ^ .________ jP

■Г Filename. f

Line number: 66

∙’1

S

,..λ ws,{

‘^. — ~ -………………………………………………………… —

"Actions’ ∙≈ ■———— ————————————

I Stogewcutlcn

∕ √∙ У — y> U∙∙ ∙.∙ . -:j

J

. P LgB messaBe. .b

.1

I EtaluSrte Expression xessaje

J

I Γ^Onlylog agression

J

cβndwon: passcount jthelpрис. 29.13. использование диалогового окна breakpoint properties для отмены остановки выполнения программы в точке останова. программа будет выводить данные на стандартное устройство выводаДавайте потратим несколько ми­нут на изучение диалогового окна Breakpoint Properties, которое откры­вается в ответ на щелчок правой кнопкой мыши на точке останова, ус­тановленной в строке 66. Рассмотрим вид окна свойств точки прерывания, показанного на рис. 29.13. На рисун­ке видно, что опция остановки вы­полнения программы в точке остано­ва отключена Зачем это нужно? Разве сама суть точки останова заключается не остановке выполнения программы в определенной точке и предоставле­нии возможности исследования со­стояния программы? Да, именно с этой целью точки прерывания и ис­пользуются. Но они могут приме­няться и для других целей, например, для исследования протоколирован­ной информации.

В поле Evaluate Expression (Вычислить выражение), которое можно видеть на рис. 29.13, для отладчика определяется, что он должен выводить состояние строковой переменной с именем message. Фактически настройки точки останова указывают отладчику не останавливать работу программы по достижении этой точки останова и выводить на экран текущее состояние переменной message.

Для демонстрации описанной возможности на практике щелкните на зеленой кнопке продолжения выполнения программы, расположенной в нижней части от­ладчика (она рассматривалась в разделе "Управление отладчиком"). После возоб­новления выполнения программы щелкните на кнопке форме два или три раза. Те­перь точка останова в строке 66 не останавливает выполнение программы. Более того. Она будет выводить данные в панель сообщений, как показано на рис. 29.14.

Сообщения, передаваемые отладчику, выглядят следующим образом

Мое сообщение

Hit breakpoint in class Simpledebug-Framel, at line 66

(Достигнута точка останова в строке 66 класса Simpledebug. Framel)

Log Expression: message = "Мое Сообщение"

(Протоколируемое выражение: message = "Мое сообщение")

Первая строка представляет собой результат вызова метода System. out. println, выводящего сообщение на стандартное устройство вывода. Следующая строка гене­рируется отладчиком и указывает, что выполнение программы достигло точки оста­нова. И, наконец, последняя строка предоставляет состояние переменной message. Конечно, в рассматриваемой программе значение переменной message не измени-
ется, но не нужно обладать сильным воображением, чтобы понять, насколько по­лезным может оказаться отключение прерывания программы в точке останова. Оно позволяет вам быстро вывести данные на экран, практически так же, как это было при использовании метода System. out. printin в начале этой главы. Разница зак­лючается в том, что этот последний метод не требует внесения изменений в код.

Отключение точек останова

Точки останова можно включать и отключать, не удаляя их. Для этого переклю­читесь на вид точек останова, показанный на рис. 29.11. Выполните щелчок правой кнопкой мыши на точке останова и снимите отметку с флажка Enable breakpoint (Разрешить точку останова). Это позволит игнорировать точку останова, не удаляя ее. Если вы удалите точку останова, для ее восстановления вам придется снова ее со­здавать, что может быть скучным и неприятным занятием, особенно если в диало­говом окне точке останова требуется внести множество изменений.

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

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

Void jButtonConditional_actionPerformed(ActionEvent Е) {

Double j;

For (int i = O; i < 10; i++)

{

1j = math.pow(i, 2.0);
system.out.printin("значение j: " + ɔ) ;
рис. 29.14. вот так
выглядит окно отладчика после определения точки останова, которая только выводит информацию на стандартное устройство вывода

рис. 29.15. настройка условной тонки останова, которая срабатывает как только переменная i получает значение 5В приведенном методе содержится цикл, выполняемый десять раз. Пошаговое выполнение одного и того же цикла десять раз может оказаться достаточно утомитель­ным. При использовании условных точек останова выполнение программы можно ос­тановить, когда переменная i получит опре­деленное значение (например, 5).

На рис. 29.15 показано диалоговое окно Breakpoint Properties с установками, кото­рые позволяют выводить данные в окно сообщений только в том случае, когда зна­чение переменной I Равно 5. Результат ра­боты программы в панели сообщений будет выглядеть следующим образом:

Значение j: 0.0

Значение j : 1.0

Значение j: 4.0

Значение j: 9.0

Значение j: 16.0

Hit breakpoint in class Simpledebug. Framel, at line 109

Log Expression: j = 25.0

Значение j: 25.0

Значение j: 36.0

Значение j: 49.0

Обратите внимание, что флажок Stop execution (Остановить выполнение) не уста­новлен, флажок Log message (Протоколировать сообщение) установлен, в поле Evaluate Expression (Вычислить выражение) находится имя переменной j, а в поле Condition (Условие) содержится условие i == 5.

примечаниеНесложно заметить, что условные точки останова срабатывают достаточно мед­ленно. Такое замедление наблюдается не только в JBuilder, но в средах Delphi и C++Builder. Как результат, условные точки останова желательно использовать толь­ко в случае крайней необходимости.. Тем не менее, когда они действительно необхо­димы, они вполне заслуживают тех нескольких секунд замедления, которые влечет за собой их применение.

Не забывайте, что условные точки останова не будут работать, если приложение запущено не в режиме отладки. Так, если вместо кнопки Debug вы нажме­Те Run, точки останова не будут прерывать выполнение программы.

Вид загруженных классов (Loaded Classes View)

Предпоследний вид, предоставляемый отладчиком, позволяет просматривать классы, загруженные во время данного запуска программы, а также статические дан­ные, связанные с определенным классом. Помните, это не С/С++, кроме того, в Java отсутгтвует препроцессор. Как результат, во время, выполнения программы вы имеете возможность определять значения констант.

Вид классов с заблокированной трассировкой (Classes with Tracing

Disabled View)

Последний вид отладчика (последняя пиктограмма, показанная на рис. 29.8) позволяет определить, какие классы заблокированы для использования в режиме интеллектуального пошагового выполнения, который был рассмотрен выше в этой главе. В редакциях SE и Enterprise можно выполнить щелчок правой кнопкой мыши на этом виде и добавить или удалить классы в списке режима интеллектуального по­шагового выполнения.

Использование отладчика

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

Устранение ошибки в программе

Рассмотрим метод, предназначенный для возврата первого слова строки:

Public static final String getFirstWord(String value)

{

∕∕ Удалить пробели

String CleanValue = value. trim();

∕∕ Определить индекс первого пробела

Int IndexOfFirstSpace = CleanValue. indexθf(, ‘);

рис. 29.16. интерфейс программы simpledebug// Если строка содержит всего одно слово, вернуть его if (IndexOfFirstSpace == 0)

{

Return CleanValue;

}

// Вернуть первое слово строки return CleanValue. subs tring(O,

IndexOfFirstSpace);

I

Если приведенному методу пере­дать строку "Грубость начальника — выдержать проще, нежели его не­компетентность", Он вернет слово "Грубость", По крайней мере, теоре­тически. На практике в коде метода содержится ошибка. Кое-кто из про­граммистов скажет, что наилучший способ обнаружения ошибки в программе — чи­тать код до тех пор, пока ошибка не будет найдена. Многие разработчики отметят, что это достаточно простой способ. Другие же могут потратить слишком много вре­мени и, не найдя ошибки, воспользоваться отладчиком.

Тем не менее, в качестве примера давайте попробуем найти ошибку с помощью от­ладчика. Добавьте приведенный метод в программу SinpleDebug и поместите на форму еще одну кнопку и элемент управления JTextArea, как показано на рис. 29.16.

В обработчик событий щелчка на кнопке First Word Bug (Ошибка с получением первого слова) добавьте следующий код:

Void jButtonFirstWord_actionPerformed(ActionEvent Е)

{

GetFirstWord ("Sam") ;

}

После запуска программы и щелчка на кнопке ActionPerformed Вы получите следующую ошибку:

Exception occurred during event dispatching:

Java. Iang. StringlndexoutofBoundsException: String index out of range: -1 at java. lang. String. substring(String. java:1525) at simpɪedebug. Framel. getFirstWord(Framel. java:89) at Sinpledebug. Framel. jButtonFirstWord_actionPerformed (Framel. java: 94) at siπpledebug. Framel_jButtonFirstWord_actionAdapter. actionPerformed(

Framel. java:122)

At javax. swing. AbstractButton. fIreActionPerformed(

AbstractButton. java:1450)

Etc…

(Возникло исключение во время обработки событий:

Java. Iang. StringlndexOutOfBoundsException: Выход за пределы индекса в строке: -1

В Java. Iang. String. substring(String. java:1525) В Simpledebug. Framel. getFirstWord(Framel. java:89) В Sinpledebug. Framel. jButtonFirstWord_actionPerformed(Framel. java:94) В Sinpledebug. Framel_jButtonFirstWord_actionAdapter. actionPerformed(

Framel. java:122)

В Javax. swing. AbstractButton. fIreActionPerformed(

AbstractButton. java:1450)

И т. д.)

примечаниеДля определения того, что же произошло, установите точку останова на вызове метода getFirstWord и перезапустите программу. Щелкните на кнопке First Word Bug. Выполнение программы остановить на вызове метода getFirstWord, как пока­зано на рис. 29.17. Для входа в метод нажмите клавишу F7 или щелкните на пиктог­рамме Step Into, как показано на рис. 29.18.

При использовании клавиш F7 или F8 для пошагового выполнения кода не­обходимо убедиться, что окно отладчика активно. В противном случае отладчик не будет ре­агировать на нажатия клавиш. Чтобы гарантировать, что все сделано правильно, щелкните Мышью на строке кода, выполняющееся в настоящее время, а затем нажмите F7 или F8.

При попадании на начало метода (см. рис. 29.18) код выполняется без ошибок. Вы можете просмотреть значение, которое передается методу в качестве аргумента. На данный момент оно равно строке "Sa∏r.

Тем не менее, на рис. 29.19 уже можно определить, в чем заключается ошибка. На этом виде программы я выполнил еще три строки кода. В окне просмотра пере­менных справа внизу можно увидеть три переменных:

Value = "Sam" cleanZalue = "Sam"

IndexOfFirstSpace = -1

R ZPuiIdtr 7 — C ava∕jbbook∕l>ebug∕Ξir4p1t∙0^btιgj⅛ cΛ>ιmp(e-debug∕Frarr5e1 java

FUe Ean Search View Project Run Team Wtearas Tools window Help Ь fflφ’∙⅞)β= ∙√*«*■*»,,*« ⅛J MjconflmDIr <‘⅛ *∙’ ;♦

Рис. 29.17. Останов выполнения программы в отладчике

⅛it? & й Φ. SlmptoOfc — — ⅝⅝lrnpMD∙bug∣pι

4fr «Project Source*

Φ SlmPltdebU.- -$j| SimpieDebughtrrf_____________________ . — X

.ιJ⅛⅛nports ‘⅛ ⅜Frame1 % JFrame FramelO ⅜ gιtFlrelWord(8tring value ⅝

Cz⅛ Framel J

Void )ButtonFlcstVocd_accionPftzfoE»ed(JLctionEvent e)

.. *1 ; j

FnimfllLrrrfl’- BfluM⅛⅝fl^tBfl⅞⅞J o⅛Jw>⅝i

ActloπPerformβdO 122, SlmpIedebugFrame AreActtonPertiDrmedO 1450. iavax. swt∩gAbs, SCtIonPerformedO ■ IsoijsvaiLswlngAbstraerr AreAcnonPerformedO: 37β. Jevex ewJng. Defet.. SelPressedO: 250, Jsvaxevrfng. DetsunSutton mouseRelessedO: 216, )avaxswtngplafbβs^ ProcessMouseEventO 371 S, Java. avΛCompι ProeessEventC: 3544Jeve awt Component, Ё ProcessEventO. 1164 Java SWtContaInerl Cc^ ⅛⅛⅛⅛5⅞aj⅛⅛⅛J⅛⅛ ^¾ħ⅛!ft ‰:

Г PMflbugFramflI βiMl

ι ’ 1 ⅛ ∙J ∙: IavaawteveKActlonEvent={Java

{Java awle⅛entAcCσnEventβ

Fi’⅝ * δ •* ’ ∙ —

B^BflBfltlPflBflt. 88 T>⅛mpH4flflug

‘ MUilder, G,,5 : — VjbboowDebugZSimpIeDebi, »tɪmpledebug/fiem_ 1 ). ⅛a

FHe Edit Search View Project Run Team Wteards Tools Window Help O ⅛ ∙tfj* n,*β > MjconflmiDir"

Jt. ⅛, <i⅛’ ‘

,∙⅛*∙

Рис. 29.18.

Вход в метод, содержащий ошибку

⅛flJ∣T 3 M«mAt

<αJ SlmpleDebugjpx i ⅛φ. «Project Source*

⅛ -)⅜ Slmpledebug

SimpleDebug. Nml ? *⅛ SlmpleDebugJava

•8 f⅛i Imports

.⅛ 0Framei ■ % JFreme j∙ * FramelO? ⅛ getf kstWord(8tnng vaiur’”

PracessWtrMJθwEvert(W > ∙∕∙ IeuaonBreikpolnLecte ;• ¼ JButtonFirstWorcLactlonF

•7 Get Uus index M u*e fxxvt τρac⅛

!at IndexOfFlEBtSpace ■ CleanValne. IndexOf(♦ ‘);

/.’ if Uuzκc зг «sly cvs∙j Oor,-i i∙5 thtɪ βtxlng. lt:turn it

If (IndexofFlcstSpace “» OJ

Ks.________________ ʃ:s ^⅛fe≈^≈^ ~~≈√*∙

Rnκtt⅛w « .∙"λ∙.λ z…… ;’, .4√r.. χf»… TL< *β.

¾w⅞l >

JS -∙f value — JavalangString = "Sam*

W∙∙iι ■ a∙ L⅛.

Z^ 3uiider 7 * G^sreJava/jbbook/D jbug∕S5mpteDebug∕4rc∕slmpledi*bug∕F ‘afrιt∙t ja√a

FHa Edit 8βarch View Project Run Team Wizards Tools Wflndnw Help

O e’-⅛ifl ⅛⅛i⅛⅛>τ⅛⅛ β MjconnrinDii ⅜T⅜*∣⅛∙>∙√fe<¼∙i

A⅛ * * J e

X⅛ Frflmfltj

Ft ið ьЗ> ∣O ®«та*ог

ɔ SimpIeDebug ∣px Ж Φ «Project Source*

K 8knpleDebufl. html. <h SimpleOehyq Java, .JX

⅛ i:$ Imports ɔ

ʒ ¾Frame1

S % JFrame FrameIO

:- ⅜ OetFlrsAVorcHStrIng value — : ⅛* procesflWmdowEvent(WI

‘ IButtonDreaMjoInLartior √⅛ JθuβoπFlrstWord-artlo∩Fχ> ⅝ bordeiLayoutl

Ta CnrrtarMPi

.<rf ∙ MB ⅛> Sf «в

Stxing CleanVelue — value. tEia(};

∕/ C«v «us Iiviftx ftf r4ift first rpace

Iat IndexofFlcstSpace — CleariValue. IndexOff’ );

HflrtlflIJflKfl

8⅝⅛,Bι-¾∣B " ⅛J∙⅛

⅜t AWT-EventQueue-O

Я JSuflonFlrelWOrd_arttonPerformedO β4.

S ScAonPertormedO’ 122. Slmpledebug Frar I AreActlonPerformedO 1450. JavajLswingA 5 SrtionPertormedO 1504. JavaxswingAbst

∣. — &

Kf’ value: JavaIanaString = "Sam"

I, ‘ Is5 9 CleanValue:javaIang String»"Sam*

3⅝j IndexOIFirstSpace: Int= -1

>i OtH JV

Рис. 29.19. Ага, вот он, источник ошибки!

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

Java. Iang-StringlndexoutofBoundsException: String index out of range: -1

Значение переменой IndexOfFirstSpace равно -1, и сообщение об ошибке го­ворит о том, что индекс находится за пределами допустимого диапазона значений.

Следующие несколько строк метода выглядит так:

// Если строка содержит всего одно слово, вернуть его if CindexOfFirstSpace == 0)

{

Return CleanValue;

}

Эта часть кода предназначена для прекращения выполнения метода, если стро­ка, переданная в качестве аргумента, содержит всего одно слово. Именно такая ситу­ация имеет место в нашем примере, тем не менее, вы видите, что значение индекса indeχθfFirststring равно -1, а не 0. Способ устранения ошибки должен быть оче­виден. Для устранения ошибки следующую строку кода можно заменить на такую:

If ((IndexOfFirstSpace ≈0) ∣∣ (IndexOfFirstSpace == -1))

Кроме того, после анализа можно сказать, что маловероятно, чтобы значение пе­ременной IndexOfFirstSpace было равно о, поскольку выше находится вызов мето­да trim. Поэтому приведенный ниже вызов также может устранить ошибку:

If (indexθfFirStSpace = -1)

Или же можно записать так: if (indexθfFirstSpace <= 0)

Таким образом, отладчик помог найти ошибку. Противники использования от­ладчиков могут возразить, что в данном случае ошибку столь же быстро можно было обнаружить с помощью простого анализа кода метода. И, возможно, это так, однако отладчик помогает более тщательно исследовать код программы.

примечаниеТем не менее, справедливы доводы как противников, так и защитников отладчи­ков. Идеальная стратегия предполагает тщательный анализ кода и его выполнение в отладчике в пошаговом режиме. Крайности вряд ли можно считать оптимальными решениями. Как всегда, хорошие доводы можно услышать от обеих участвующих в споре сторон.

Методы, описанные в начале этой главы, также можно было использо­вать для обнаружения ошибки в приведенном коде. Например, для тестирования метода можно было воспользоваться следующей программой:

String s = getFirstWord("Sam is red hot");

Assert (s. equals("Sam"));

S = getFirstWord("Sam");

Assert (s. equals("Sam"));

S = geXFirstWord("");

Ansert (s. equals (" " ) ) ;

Если метод сможет выполнить все эти операторы, можно быть уверенным, что он не содержит ошибок. Если пользователь обнаружит случай, когда метод выполняет­ся с ошибками, просто введите новый оператор Assert. И Повторюсь еще раз, ана­логичный подход используется в утилите JUnit, поэтому более подробно его можно будет изучить в следующей главе.

Отладка потоков

И последний шаг нашего путешествия по стране отладки — рассмотрение мето­дов, которые позволяют отыскать ошибки в коде, работающем с несколькими пото­ками.

Программа DebugThread, Входящая в состав сопровождающих книгу материалов, включает класс, выполняющийся в отдельном потоке. Код вызова потока выглядит следующим образом:

Void jButtonl_actionPerformed(ActionEvent Е)

{

MyThread myThread = new MyThread () ; myThread. addActionListener(this); myThread. start();

примечание}

Класс Framel, к которому принадлежит приведенный выше код, обо­значен как класс ActionListener для потока. Это означает, что класс Framel в своем заголовке должен содержать конструкцию implements ActionListener. Добавьте код обработки события:

Public void BCtionPerformed(ActionEvent parrol) (

// Код обработки событий

)

Для написания этого кода можно воспользоваться BeansExpress или мастером Interface Wizard. Кроме того, код можно ввести и вручную, поскольку его размеры не очень велики. Если у вас есть вопросы, откройте соответствующий код из сопровож­дающих материалов.

примечаниеКод метода ActionPerformed Сначала создает класс MyThread Потомок класса Thread.

Ранее в этой книге я приводил пример еще одного класса, выполняю­щегося в потоке. Тот первый класс реализовывал интерфейс Runnable и не являлся по­томком класса Thread. Я уже говорил о том, что класс, выполняемый в потоке, удобнее создавать на основе реализации интерфейса Runnable, а не на основе потомка класса Thread. Это справедливо во всех случаях. При создании нового класса от класса Thread он получается чересчур большим. Тем не менее, в нашем случае просто приводится при­мер альтернативной реализации класса, выполняемого в потоке. Первая программа с та­ким классом называлась CustomMessageSender и была рассмотрена в части Ill книги. Описание программы CustomMessageSender было гораздо более подробным, чем бу­Дет приведено в этой главе.

После создания экземпляра класса Thread код использует текущий класс в каче­стве класса ActionListener. После этого запускается выполнение потока.

Потомок класса Thread Содержит очень простой метод Run, Который создает объект ArrayList. Затем метод Run Вызывает серию событий ActionEvents, Каждое из которых инкапсулирует один элемент ArrayList. Класс Framei Получает список и выводит его содержимое пользователю. Код класса Thread Можно найти в листин­ге 29.1, а код потомка класса JFrame, Являющегося слушателем для класса Thread, В листинге 29.2.

Листинг 29.1. Потомок класса Thread, создающий список строк и передающий их в основной класс в качестве части события

Package debugthread;

Import java. util.*;

Import java. awt. event.*;

Public class MyThread extends Thread

{

Public MyThread()

{

)

Public void run ()

(

ArrayList list = new ArrayListO; list. add("Sam");

Iist. add("foo"); list. add("tom");

Iterator itr = list. iterator(); while (itr. hasNext())

{

String data ≈ (String)itr. next();

ActionEvent myEvent ≈ new ActionEvent(this, 1, data); fIreActionPerforined (myEvent) ;

)

1

Public synchronized void XemoveActionListener(ActionListener 1)

(

If (actionListeners!= null && actionListeners. contains(1))

(

Vector v = (Vector) actionListeners. clone(); v. removeElement(1); actionListeners = v;

)

}

Public synchronized void SddActionListener(ActionListener 1)

{

Vector v = actionListeners ≈

Null? new Vector(2) (Vector) actionListeners. clone();

If (!v. contains(1))

{

V. addElement(1); actionListeners = v;

)

)

Private transient Vector actionListeners; protected void fIreActionPerformed(ActionEvent e)

(

If (actionListeners!= null)

{

vector listeners actionlisteners;

Int count = listeners. size(); For (int i = O; i < count; i++)

{

((ActionListener) listeners. elementAt(i)).actionPerformed(e);

}

)

}

)

Листинг 29.2. Класс Frame1, который является слушателем для класса MyThread

Package debugthread;

Iɪnport java. awt.*;

Import java. awt. event.*;

Import javax. swing.*;

Import java. util.*;

Import com. elvenware. comp.*;

Public class Framel extends JFrame Inplements ActionListener

(

JPanel ContentPane;

BorderLayout borderLayoutl = new BorderLayout();

JButton jButtonl = new JButton();

JPanel jPanell = new JPanel ();

ElfListBox elfListBoxl = new ElfLrstBox();

BorderLayout borderLayout2 = new BorderLayout();

∕ ∕ Создание фрейма Public Framel()

{

OnableEvents(AWTEvent. WINDOW_EVENT_MASK); try <

Jbɪnit();

)

Catch (Exception e)

{

E. printStackTrace();

}

)

∕∕ Инициализация компонент Private void jbɪnit() throws Exception {

ContentPane = (JPanel) this. getContentP⅛ne(); jButtonl. setText("jButtonl");

JButtonl. addActionListener(new java. awt. event. ActionListener()

<

Public void actionPerformed(ActionEvent e)

(

JButtonl_actionPerformed(e)I

}

)) ;

ContentPane. SetLayout(borderLayoutl); this. setSize(new Dimension(400, 300));

This. setTitle("Frame Title"); jPanell. SetLayout(borderLayout2);

ContentPane. add(jButtonl, BorderLayout-SOUTH); contentPane. add(jPanell, BorderLayout-CENTER); jPanell. add(elfListBoxl, BorderLayout-CENTER);

)

// Перекрыт, чтобы можно было выйти при закрытии окна Protected void processWindowEvent(WindowEvent e)

{

Super. ProceasWindowEvent(е);

If (e. getID() = WindowEvent. WINDOW_CLOSING)

{

System. exit(О);

}

}

Void jButtonl_actionPerformed(ActionEvent e)

{

MyThread myThread — new MyThread(); myThread. SddActionListener(this); myThread. start();

}

Public void actionPerformed(ActionEvent e)

{

ElfListBoxl. setstring(e. getActionCommand());

Установите в программе DebugThread Две точки останова. Первая должна нахо­дится в методе ActionPerformed, Который создает и вызывает экземпляр потока. Это строка 74 класса Framel:

Void jButtonl_actionPerformed(ActionEvent e)

{

MyThread myThread = new MyThread () ; // Установите точку останова здесь MyThread. addλctionListener(this); MyThread. start();

Вторая точка останова должна находиться в первой выполняемой строке метода Run Класса MyThread:

Public void run()

{

ArrayList list = new ArrayList(); // Установите точку останова здесь List. add("Sam"); List. add(,,foo") ; List. add("torn");

Iterator itr = list. iterator(); while (itr. hasNext())

{

String data = (String)itr. next();

ActionEvent myEvent = new ActionEvent (this, 1, data) ; fireActionPerformed(myEvent);

}

}

На рис. 29.20 показан вид потоков отладчика при прерывании выполнения про­граммы на первой точке останова, а на рис. 29.21 — состояние отладчика при оста­нове на гторой точке останова.

На рис. 29.20 можно увидеть, что активный поток обозначен маленькой красной точкой. Конечно, на черно-белом рисунке вы не видите цветов, тем не менее, точка на потоке должна четко просматриваться. Точка означает, что данный поток акти­
вен. На рис. 29.21 вы видите, что в список потоков добавился новый поток. Он на­зывается Thread-2 и теперь красная точка находится возле него. В настоящий мо­мент именно второй поток, Thread-2, является активным потоком программы.

Потоки, отмеченные изображениями желтых катушек, — это заблокированные потоки, потоки с синими катушками — являются активными, а с черными — выпол­ненными.

На рис. 29.21 обратите внимание, что в правом окне содержатся все активные пе­ременные потока. Значение этих переменных можно исследовать точно так же, как мы это делали с переменной Message Выше в этой главе.

Теперь вы ознакомлены со всеми основными факторами, которые необходимо понимать для эффективной отладки потоков в JBuilder. Столь же простая, сколь и удивительная правда заключается в том, что JBuilder позволяет проанализировать каждый отдельный поток программы. Если вы правильно установите точки остано­ва, то сможете входить в каждый поток и определять состояние каждого из них.

udder,file edit 8earch view pro∣e
qtf8∙⅞⅛⅛a
ιa --⅜f#*-’ tf & 2pn*> -
1 Φ Φ debugthread *
⅛ debuattireadjava tt run team wteards tools window help
7 ж r Λi~3"bs^⅜ ⅛7s⅛ 7 
j^y∣⅝ .∙ , ,j ,ʃ,
m ⅞imiιrthhu4 xi s tremelf or ⅛j,y∣h∏>aπ * -⅛ool-cti
-⅛∣.
void jduttonl-acclonpetfotmed (actlonzvent e)
.Φ
i 83∙ ¾ imports 3
sb∙ 0 framel
i % jframe ⅛*
s - -ft actiontjstener
frameio
* actionperformed(ae -⅜j
⅞ ⅜j 1. ... ⅛o ► bythreed-bddictionllscener(this);
* ∙ bythrcnd-starco: ∖j
 boutteldeslgni bear. ∣j>⅛ }θo⅜∣ mhitoiyl 1~^"*

,g /src java∕jbbσσk∕debug∕debugtbreβd∕src∕debugtħread∕f,рис. 29.20. перед тем, как новый поток будет создан, можно видеть четыре узда в главной ветви, расположенной елевой части окна потоков,sf ja ⅛) svstem,sfcj
⅜ 4
,ft suntoalkltpostevsntoueue-o h ⅛ √1 awt-windows
sj> thrssd-i
sti- ей reference hsndler flnsltzer
æ √t iignsl dispatcher
3i√* compiiethreado
s √t thread-o

Если вы новичок в программировании, этот экскурс в отладку потоков может по­казаться вам второстепенной информацией. Тем не менее, это маленькое, но все — таки чудо. Разработчики JBuilder, создавшие отладчик, заслуживают высокой похва­лы за свой труд. Хороших слов в свой адрес заслуживают и разработчики из компа­нии Sun. Когда вы сталкиваетесь с такими технологиями, где весь код, включая отладчик, написан на языке Java, вы вдруг начинаете осознавать, что Java быстро вы­ходит на лидирующие позиции среди первоклассных языков программирования.

Напоминания и советы

В заключение главы хотелось бы напомнить, что в интегрированной среде JBuilder имеются (по крайней мере) две кнопки зеленого цвета, связанные с запус­ком на выполнение. Одна из них позволяет запустить программу, а вторая предназ­начена для запуска программы под управлением отладчика.

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

В тексте книги я несколько раз просил не называть все главные классы программ Applicationl. Даже беглого взгляда на рис. 29.22 будет достаточно, чтобы по­нять, зачем этого не следует делать. При одновременной работе с несколькими проектами Их гораздо проще разграничить, если имена их основных классов будут отличаться.

рис. 29.22. обратите внимание на закладки в нижней части интегрированной среды разработки. здесь имеется две копии программы debugthread, одна simpledebug и две копии application 1

Для выбора закладки необходимо щелкнуть на ней правой кнопкой мыши. В JBuilder на закладках присутствует символ X, который служит для закрытия заклад­ки. Тем не менее, самый простой способ закрытия вкладок заключается в следую­щем: щелкните правой кнопкой мыши на закладке и в контекстном меню выберите пункт Remove all tabs (Удалить все закладки). В результате все закладки закрывают­ся. Если при выполнении этой операции в JBuilder имеются загружены программы, будет выведено сообщение о необходимости их закрытия. При таком закрытии про­грамм с какими-то проблемами я не сталкивался. Тем не менее, в других версиях JBuilder время от времени может возникать ошибка утечки памяти Для ее устране­ния интегрированную среду разработки необходимо закрыть и снова открыть.

Сборка мусора

Средство OptimizeIt, разработанное компанией Borland, позволяет подробно изучить принцип сборки мусора (garbage collection). Тем не менее, существует очень простой метод, который дает широкий простор для исследования процессов, про­исходящих при обработке программы сборщиком мусора Java. Метод заключается в запуске программы с ключом -verbose :дс.

В частности, выберите в меню пункт Project, Project Properties в среде JBuilder и перейдите на страницу Run. Отредактируйте текущую конфигурацию программы времени выполнения, включив в список параметров виртуальной машины ключ — verbose:ge, как показано на рис. 29.23.

Рис. 29.23. Передача ключей для запуска виртуальной машины Java, Которые позволяют оценить время работы сборщика мусора, а также объем памяти, освободившийся в результате

Результаты работы программы при ее запуске с указанным ключом можно уви­деть в панели сообщений:

[GC 1254K->745K(1984K), 0.0051940 secs]

[GC 1257K->746K(1984K), 0.0013247 secs]

[GC 789K->746K(1984K), 0.0006990 secs]

[Full GC 746K->746K(1984K), 0.0808960 secs]

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

Опции -Xms и — Xmx, передаваемые виртуальной машине, позволяют изменить работу сборщика мусора Java. На момент публикации книги более подробную ин­формацию можно было найти по адресу Http://java. sun. com/docs/hotspot/gc/.

Резюме

В этой главе вы ознакомились с отладкой Java-программ. В начале главы были описаны традиционные мощные средства отладки, записывающие данные на стан­дартное устройство вывода или в журнальные файлы. Кроме того, в главе был приве­ден короткий раздел, посвященный утверждениям.

Затем мы перешли к рассмотрению установки точек останова в программах в сре­де JBuilder и анализу текущего состояния приложения или аплета. Далее были опи­саны различные виды, предоставляемые отладчиком. Сюда входили виды текущих переменных и потоков программы, виды загруженных классов и их статических дан­ных, вид слежения за переменными и выражениями, вид точек останова и, наконец, вид, предназначенный для блокирования и разблокирования классов для пошаго­вого выполнения.

Ближе к концу главы был приведен пример обнаружения и устранения ошибки в программе с помощью отладчика. И в самом конце был кратко рассмотрен пример отладки программ, содержащих потоки.

Я не рассматривал удаленную отладку или использование при отладке средства OptimizeIt. Средство OptimizeIt особенно полезно для исследования процесса рабо­ты сборщика мусора.

Хоть эта глава находится во второй половине книги и ее размер не слишком ве­лик, тем не менее, она является одной из важнейших. Если вы только-только начи­наете работать с отладчиком JBuilder, я надеюсь, что здесь вы найдете достаточно информации для того, чтобы приступить к серьезному изучению одного из наибо­лее полезных, эффективных и действительно удивительных средств всей среды JBuilder.

Чарли Калверт

Глава 30

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *