Е. Буткевич Пишем программы и игры


Глава 11 Работа со временем, датой и календарем



страница10/15
Дата22.06.2019
Размер2.79 Mb.
ТипКраткое содержание
1   ...   7   8   9   10   11   12   13   14   15
Глава 11

Работа со временем, датой и календарем

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

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

Класс Date

Объект класса Date представляет собой текущее время с точностью до миллисекунд. Время представлено в миллисекундах, прошедших с полуночи 1 января 1970 года. Информация, безусловно, нужная, но в таком виде совершенно бесполезная. К со­жалению, класс Date не содержит интерпретаторов для перевода даты в более по­нятный для нас формат. Для этого нужно использовать класс Calendar, который мы рассмотрим позже.

Класс Date имеет всего несколько методов. Все они оперируют с датой и временем лишь в указанном формате. Рассмотрим эти методы:


  • Date() — конструктор; создает новый объект даты, содержащий текущее время;

  • Date(l ong date) — конструктор; создает новый объект даты, содержащий время,
    заданное в аргументе date;

  • boolean equals(Object obj) — возвращает значение true в том случае, если две
    даты идентичны с точностью до миллисекунды;

  • long getTime() — возвращает время, представленное объектом даты;

  • void setTimeflong time) — устанавливает объект даты в момент времени, пред­
    ставленный параметром time.

120

Глава 11. Работа со временем, датой и календарем

Вот, собственно, и все. Разнообразием и гибкостью методов класс Date нас не ра­дует. Самое время сформулировать задачу, которую мы хотим реализовать. К про­грамме записной книжки, которую мы разбирали в прошлой главе, добавим фун­кцию напоминания о днях рождения записанных абонентов. Для этого потребуется расширить формат записи, содержащейся в хранилище записей, добавив поле даты рождения. В сценарий ввода данных о новом абоненте потребуется добавить эк­ран для ввода даты рождения. Здесь нас ждет приятный сюрприз, потому что поле ввода даты предоставляет нам пользовательский интерфейс высокого уровня в виде класса DateField.

Класс DateField

Класс DateField является потомком класса Item, то есть для его демонстрации на экране нам потребуется еще и форма. Поле может работать в трех режимах ввода: ввод только даты, ввод только времени, ввод даты и времени. При вводе только времени дата по умолчанию будет соответствовать 1 января 1970 года. Для рабо­ты с полем ввода класс DateFi eld предоставляет следующие методы:

DateFi el d( String 1abel . intmode) — конструктор; создает поле ввода даты с за­головком 1abel. Режим поля ввода определяется аргу­ментом mode, который может принимать значение од-ной из следующих определяющих констант:

• DATE — ввод только даты;

■ DATE_TIME — ввод даты и времени;

• TIME — ввод только времени;



  • Date getDateO — возвращает введенное значение
    даты и времени в формате класса Date. При созда­
    нии объекта исходное значение даты и времени не
    определено, поэтому при запросе отсутствующей
    введенной даты будет возвращено значение nul 1;

  • intgetInputMode() — возвращает режим ввода поля
    в виде определяющей константы;

  • void setDate(Date date) —устанавливает в поле ввода
    новое значение, представленное параметром date;

ш voi d set InputMode( i nt mode) — устанавливает новый режим ввода, заданный аргументом mode в виде оп­ределяющей константы;

■ void setLabel (String l abel) — устанавливает новый


заголовок поля ввода.

Поскольку поле ввода даты предоставлено интерфей­сом высокого уровня, то внешний вид поля и логика

ввода зависят от конкретной модели телефона. Напри-
Рис. 11.1. Экран установки r r

даты в стандартной8™ меР> в стандартном эмуляторе от WTK поле ввода даты

эмуляторе WTK выглядит следующим образом (рис. 11.1).



Класс DateFieid 121

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

import javax.microedition.1cdui.DateField: import java.util.Date; import java.util.Calendar:

private Form dateForm; // форма ввода дня рождения

private DateFieid dateField: // поле ввода дня рождения

В методе startApp() проинициализируем поле ввода даты аналогично полям вво­да остальной личной информации:

// экран ввода дня рождения

dateField = new DateField("Birthday". DateFieid.DATE):

dateForm = new FormC'"):

dateForm.append(dateField);

dateForm.addCommand(next):

dateForm.addCommand(back);

dateForm.setCommandListener(this);

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

Экран информации записи будет теперь формироваться следующим образом: // если команда вызвана из экрана со списком имен if(d==nameList) { try {

// создать объект даты рождения

Date birthday = new Date(dis.readLongO);

// создать объект поля ввода даты

DateField df = new DateField("\DateField.DATE):

// установить дату рождения в поле ввода даты

df.setDate(birthday):

// добавить даты рождения в форму отображения параметров

infoForm.append(df);

di splay.setCurrent(infoForm);



122 Глава 11. Работа со временем, датой и календарем

Запись, в свою очередь, будет формироваться так:

try {

// записать введенные параметры в поток вывода



dos.wri teUTF(tbName.getString());

dos.writeUTF(tbPhone.getStr i ng O)):

dos.wn teUTF(tbEMail.getStnngO):

dos.wri teLong(dateField.getDateO.getTimeO);



II добавить запись в хранилище

recordStore.addRecord(baos.toByteArray(), 0. baos.sizeO):




у С корректной сменой экранов при обработке команд Next и Back, думаю, вы справитесь самостоятельно. Те­перь во время ввода нового контакта появится поле ввода даты рождения, а форма информации об абонен­те будет выглядеть как на рис. 11.2.

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

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

Класс Calendar

Класс Calendar является абстрактным классом для ра­
боты с датой и временем, содержащим набор констант,
представляющих дни недели и месяцы. Для работы
с месяцами определены константы от JANUARY до DECEMBER,
Рис. 11.2. К информации об а для Рао°ть[ с днями недели константы от HONDAV до
абоненте добавлена дата SUNDAY. Поскольку класс Calendar является абстрактным,
рождения мы не можем просто создать объект этого класса, но мы

можем получить его с помощью специального метода:

■ static Calendar getlnstanceO — получить объект календаря, представляющий
текущие дату и время.

Класс Caiendar связан с уже рассмотренным классом Date следующими методами:



  • Date getTime() — возвращает текущее время, представленное объектом кален­
    даря в виде объекта класса Date;

  • void setTime(Date date) — устанавливает календарю текущее время, представ­
    ленное объектом класса Date.

Класс TimeZone 123

Преобразование времени и даты осуществляется с помощью методов get и set:



  • intget(int field) — возвращает преобразованное значение одного из парамет­
    ров календаря. Параметр определяется аргументом field. Аргумент filed мо­
    жет принимать значение одной из следующих констант: YEAR, MONTH, DATE,
    DAY_OF_WEEK, HOUR_OF_DAY, HOUR, AM_PM, MINUTE, SECOND, MILLISECOND. Метод возвраща­
    ет значение запрошенного параметра в виде константы, определяющей месяц
    или день недели, либо числовое значение запрошенной единицы времени. Кон­
    станта HOUR_OF_DAY определяет значение часа в 24-часовом формате, а констан­
    та HOUR — в 12-часовом. Константа АМ_РМ используется в 12-часовом формате
    для определения значения «до полудня» (AM) или «после полудня» (РМ);

  • void setdnt field, int value) — устанавливает значение value в один из пара­
    метров даты или времени, который определяется аргументом field. Параметр
    DAY_OF_WEEK не может быть установлен.

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

  • longgetTimelnMi11 is() — возвращает время календаря в миллисекундах;

  • void setTimelnMi Hisd ong mil lis) — устанавливает время календаря, заданное
    параметром mi 11 is.

Класс Calendar организует сравнение времени двух календарей с помощью следу­ющих методов:

  • boolean equals(Object obj) — возвращает значение true, если аргумент obj не
    равен nul l, и представляет то же самое время, что и вызывающий объект ка­
    лендаря;

  • boolean before (Object when) — возвращает значение true, если время, представ­
    ленное вызывающим объектом, ранее времени, представленного аргументом
    obj;

  • boolean a fter (Object when) - возвращает значение true, если время, представлен­
    ное вызывающим объектом, позднее времени, представленного аргументом obj.

Кроме того, класс Calendar поддерживает работу с часовыми поясами: и TimeZone getTimeZone() — получить часовой пояс календаря;

■ void setTimeZone(TimeZone value) — установить часовой пояс календаря.



Класс TimeZone

Для полноты картины предоставляемых реализацией J2ME возможностей, рас­смотрим абстрактный класс TimeZone, представляющий часовой пояс. Класс TimeZone позволяет узнать, какой часовой пояс установлен на аппарате, выполняющем про­грамму, и осуществляется ли переход на летнее время. Класс TimeZone имеет сле­дующий набор методов:

■ String[] getAvailablelDsO — возвращает аббревиатуры всех поддерживаемых
аппаратом часовых поясов в виде массива строк;

124 Глава 11. Работа со временем, датой и календарем


  • TimeZonegetDefaultC) — возвращает часовой пояс, используемый аппаратом по
    умолчанию;

  • String getID() — возвращает аббревиатуру текущего часового пояса, использу­
    емого аппаратом;

  • int getRawOf f set () — возвращает смещение данного часового пояса относительно
    времени по Гринвичу;

  • TimeZonegetTimeZone(String ID) — получить объект часового пояса по его аббре­
    виатуре;

  • boolean useDaylightTimeO — возвращает значение true, если часовой пояс ис­
    пользует переход на летнее время (DST — Daylight Savings Time).

Класс BirthdayFilter

Теперь мы располагаем всеми необходимыми средствами для реализации функции напоминания о дне рождения в нашей записной книжке. Для выбора именинников из хранилища записей реализуем класс фильтра Bi rthdayFi l ter, который будет срав­нивать даты рождения с текущей датой и выбирать лишь интересующие нас записи:

// класс фильтра записей по дням рождения private class BirthdayFilter implements RecordFilter { // метод сравнения записей public boolean matches(byte[] candidate) { // преобразовать запись в байтовый поток

ByteArraylnputStream bais • new ByteArraylnputStream(candidate); // создать поток, поддерживающий чтение по типу DatalnputStream dis - new DatalnputStream(bais): // день рождения Date birthDate = new DateO: try {

// считать строковые параметры записи

dis.readUTFO:

dis.readUTFO;

dis.readUTFO:

// считать дату рождения

birthDate.setTime(dis.readLong());

)

catch (IOException ioe) { return false; }



// получить два календаря х текущей датой , Calendar rightNow » Calendar. get lnstanceO : Calendar birthday - Calendar. get lnstanceC); // установить дату рождения именинника Ы rthday.setTime(bi rthDate) : // сравнить день и месяц рождения с текущей датой 1f(rightNow.get(Calendar.DAY_OF_MONTH) — birthday.get(Calendaг.DAY_OF_MONTH) U

Класс BirthdayFilter 125

rightNow.get(Calendar.MONTH) ~ birthday. get(Calendar. MONTH)) return true: else

return false;

Реализуем функцию, которая будет фильтровать хранилище записей по текущей дате и возвращать имя человека, у которого сегодня день рождения, или значение nul l, если таковых не имеется:

// метод SearchBirthday возвращает строку с именем именинника; // если в этот день именинников нет. то возвращает null private String SearchBirthdayQ [ String name = null; try {

// создать объект фильтра по дню рождения

BirthdayFilter filter = new BirthdayFilterO;

// получить список записей с подходящим днем рождения

RecordEnumeration re = recordStore.enumerateRecords(filter. null, false);

// получить ID записи

int id • re.nextRecordldO;

// получить запись по ID

byte[] record = recordStore.getRecord(id):

// преобразовать запись в байтовый поток

ByteArra y lnputStream bais = new ByteArrayInputStream(record);

II создать поток, поддерживающий чтение по типу

DatalnputStream dis - new DatalnputStream(bais):

// считать из потока строку с именем

name = dis.readUTFO:

1

catch(RecordStoreException rse) {}



catch(IOException ioe) {}

// вернуть имя именинника

return name: }

Все, что нам остается сделать, это вызвать в стартовом методе приложения startApp() функцию поиска именинников и при необходимости вывести соответствующее напоминание:

// создать список имен

BuildNameListO;



Ii поиск именинника

String name • SearchBirthdayO ;

// если имя найдено

if(name!=null) {

// создать форму напоминания

126

Глава 11. Работа со временем, датой и календарем


Form remindForm = new Form("Reminder"):• // добавить напоминание в форму remi ndForm.append( name + " has a birthday today!"): // добавить команду возврата remi ndForm. addCommand(ok); remindForm.setCormiandListener(this); // отобразить форму di spl ay. setCurrent (remindForm); } else

// отобразить список имен на экране di splay.setCurrent(nameList);





Теперь все готово. При первом запуске нужно добавить контакт с текущей датой рождения, а затем заново за­пустить приложение. Если все запрограммировано вер­но, то при запуске появится сообщение, показанное на рис. 11.3.

■(ermmJei *1yOwrWlfe has a lirthdev today!

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

* * *

Итак, в этой главе мы изучили работу с датой, вре­


менем, календарем и часовым поясом. Мы рассмот­
рели лишь один пример из всего многообразия воз­
можных приложений, имеющих дело со временем
и датой. Часовой пояс, например, можно использо­
вать для интернационализации программ и автома­
тического выбора языка интерфейса. А теперь може-
Рвам"ого н1щоФпо"дравитъИТ те сДелать паузу и опробовать изученный материал,
с днем рождения В добрый путь!

Глава 12

Работа над ошибками

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


#<1) Nokia 7210 SO*
В о время выполнения программы может случиться много разных неприятнос­тей, таких как деление на ноль, выход индекса массива за допустимые пределы, неверное имя загружаемого файла и масса других. В функционально-ориет й рованных языках программирования, таких как С или Pascal, такие ситуации обрабатывались с помощью многочисленных операторов if...else, которые значительно уве­личивают как объем, так и время выполнения программы. В объектно-ориентированных язы­ках реализован другой подход к обработке вне­штатных ситуаций.

Класс Exception

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



Рис. 12.1. В случае деления на ноль программа прерывается

Остановку выполнения программы можно пре­дотвратить, реализовав в программе обработку возможных исключений. Как мы уже видели на примерах, команды, потенциально формиру­ющие исключения, заключаются в блок try{...}, а действия, которые следует выполнить в ис­ключительной ситуации, заключаются в блок catch(Exception e) {...}. В качестве аргумента опе-

128 Глава 12. Работа над ошибками

ратор catch принимает объект исключения определенного типа в зависимости от ситуации, которую мы хотим обработать. После одного блока try может следо­вать несколько блоков catch с обработкой разных исключений. Управление будет передано первому блоку, аргумент которого будет соответствовать сформирован­ному исключению. Таким образом, синтаксис блока проверки и обработки исклю­чений в общем случае выглядит так: try { ...

)

catchC...) {...}



catchC.) {...}

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

Класс Throwable и все его расширения содержат два конструктора:


  • Throwablе() — конструктор по умолчанию;

  • ThrowableCString message) — объект исключения будет содержать текстовую
    информацию, переданную в строке message.

Класс Throwable несет дополнительную информацию о сформированном исклю­чении, которую можно получить с помощью следующих методов:

■ String getMessage() — возвращает строку с текстовой информацией об исклю­


чительной ситуации. Если объект был создан пользователем с помощью кон­
структора по умолчанию, то возвращает значение nul 1;

■ String toStringO — возвращает строку с текстовым описанием исключения,


. состоящим из имени класса сформированного исключения, двоеточия (разде­
лителя) и текста, возвращаемого методом getMessage;

■ void pri ntStackTraceO) — выводит в область сообщения об ошибках название


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

Система определяет два потока вывода сообщений: поток вывода информации и поток вывода сообщений об ошибках. Потоки вывода доступны из любой точки программы. Мы можем писать туда любую полезную информацию, включая со­держимое переменных, с помощью системных методов: System.out.printlnCString text) и System.err.println(String text). В нашем случае сообщения обоих пото­ков появятся в основном окне WTK. При запуске приложения на реальном аппа­рате никаких сообщений мы можем и не увидеть.

Теперь, если деление на ноль поместить в блок try, а в блоке catch вывести в сис­темную область всю информацию о сформированном исключении следующим образом:

int n=0: try {

Класс Exception 129

int к • 5/n: } catch( Exception exc) {

System.out.printlnC'Get Massage: " + exc.getMessageO): System.out.printlnC'To String: " + exc.toStringO) : System.err.printlnC 'Print Stack Trace:"): exc.printStackTrace():

t

System.out.printlnC 'Continue program...");



то в области вывода системных сообщений мы увидим такую картину (рис. 12.2).

Ш2МЕ Wireless Toolkit - TestSample




jjfifc ' Ш Prafckt ЙЙр ■ ;;■.■■ ■ . \, '.;■-■ : ,'■:













>bt^jbefaiJIGr*yPhone




Gee Message: null




Го String: java.lang.ArithmeticException




Print Stack Trace:




java. lang. ArithmeticException




at TestSample.startApp(+2)




at javax.microedition.midlet.HIDletProx

y,startApp(+7)

at com.sun.midp.midlet.Scheduler.schedule(+225)

at com.sun.midp.dev.DevMIDletSuitelmpl.

schedule(+7)

at com.sun.midp.Hain. runLocalClass(+20)




ас com.sun.midp.Hain.main(+68)




Continue program...




Рис. 12.2. В основное окно WTK может быть выведена подробная информация об ошибке

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

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

AddressBook.Java:44: unreported exception javax.microedition.rms.RecordStoreException:

must be caught or declared to be thrown

recordStore • RecordStore.openRecordStore("Address-Book". true):

Рассмотрим некоторые наиболее распространенные исключения, формируемые реализацией J2ME и уже использованные нами в примерах. Основная группа ис­ключений, наследованных от класса RuntimeException, является непроверяемой, поэтому к ним нужно относиться особо внимательно. В наших примерах обработ­ка исключений была опущена везде, где только возможно, что не есть хорошо. ■ Arithmeti cException — формируется при ошибках в арифметических операци­ях, например при делении на ноль;

130 Глава 12. Работа над ошибками



  • ArrayStoreException — формируется при попытке записать в массив данные не­
    верного типа;

  • EmptyStackExcepti on — формируется во время работы со стеком при попытке
    получения данных, когда стек пуст;

  • П1 еда1 ArgumentExcept i on — возникает при передаче в метод некорректного зна­
    чения аргумента. Если в качестве аргумента предусмотрена константа, то луч­
    ше пользоваться ей в чистом виде во избежание подобных ситуаций;

  • IndexOutOfBoundsException — указывает на то, что используемый индекс масси­
    ва, вектора или строки выходит за пределы допустимых значений;

  • NegativeArraySizeException — формируется при попытке создания массива от­
    рицательной длины;

  • Nul lPoi nterExcepti on — формируется при попытке вызвать метод или модифи­
    цировать поле объекта, значение которого nul 1.

Исключения, сформированные хранилищем записей, наследованы от класса RecordStoreException и являются проверяемыми, поэтому для успешной компи­ляции всю работу с хранилищем мы оформляли в try...catch блоки. Возможные исключения при работе с хранилищем записей (InvalidRecordlDExceotion, RecordStoreFul1Exception, RecordStoreNotFoundExcepti on, RecordStoreNotOpenException) мы уже рассмотрели в соответствующей главе, немного забегая вперед.

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

Исключения, наследованные от класса IOExcept ion, формируются при ошибках с процедурами ввода-вывода:


  • Connect!onNotFoundException — цель соединения не найдена;

  • EOFException — конец файла был достигнут при работе с потоком ввода;

  • InterruptedlOException — формируется в случае, если операция ввода-вывода
    была прервана;

  • UnsupportedEncodingException — данная кодировка не поддерживается;

■ UTFDat a Format Exception — формируется при работе с Unicode, если символы стро­
ки не являются символами универсальной кодировки.

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



Формирование исключений

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

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

Формирование исключений 131

наличия всех аргументов в форме ввода в виде формирования исключения. Для этого реализуем класс исключения Mi ssingArgExcepti on: class MissingArgException extends Exception {

// текстовое сообщение исключения

private String msg:

// конструктор без параметров

MissingArgExceptionf){ msg - null;}

П конструктор, принимающий строку

Mi ssingArgExcepti on CString str) { msg - str;}

// метод возврата текстового сообщения

public String toString(){

return "Exception (" + msg + ")";

} \

Исключения активизируются с помощью оператора throw, который позволяет выбрасывать любые исключения иерархии класса Throwable из любого места про­граммы. Команда throw new ArithmeticExceptionO Приведет к такому асе эффекту, как если бы здесь произошло деление на ноль, и обработка этого исключения пой­дет своим чередом. Тот факт, что метод формирует исключение, обозначается в заголовке метода ключевым словом throws и названием класса исключения. Реа­лизуем метод проверки наличия аргументов в форме:

void checkArgsO throws MissingArgException {



И проверить заполнение всех полей ввода

// сформировать исключение в случае отсутствия аргумента

if(argl.sizeO—0)

throw new MissingArgExceptionC"Missing First Argument"):

ifCarg2.size()==0)

throw new MissingArgExceptionC'Missing Second Argument");

if(action.size()==0)

throw new MissingArgExceptionC'Missing Action Sign"); I

Проверка заполнения формы ввода в методе commandAction будет выглядеть теперь следующим образом: // проверить заполнение всех полей ввода try {

checkArgsO: } catchCMissingArgException maexc) {

// ошибка: не все поля ввода заполнены

resForm.append(inaexc.toStringO):

// отобразить сообщение

di splay.setCurrentC resForm);

// выйти

return:


132 Глава 12. Работа над ошибками






Если запустить программу и вызвать команду вычисления результатов, не задавая аргументов, то сформируется соответствующее исключение, а мы увидим на экране сообщение (рис. 12.3).

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



Класс Alert

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



Рис. 12.3. При отсутствии

аргументов формируется

исключение и выводится

сообщение об ошибке



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

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



  • AlertCString title) —конструктор создает пустое сообщение с заголовком title;

  • AlertCString title. String alertText, Image alertlmage. AlertType alertType) —
    конструктор создает сообщение с заголовком title, текстом alertText и кар­
    тинкой а1еrtImage. Параметр а1ertTyре задает тип сообщения, представленный
    классом А1 ertType, который мы еще рассмотрим подробнее. Параметр а1 ertType
    может принимать значение nul1 для создания обычного сообщения;

  • void addCommand(Command cmd) — разумное объяснение наличию этого метода
    придумать сложно, поскольку класс Alert не поддерживает добавление команд.
    При вызове метода будет сформировано исключение 111еда1StateException;

  • int getDefauHTimeoutC) — возвращает значение времени демонстрации сообще­
    ния в миллисекундах, устанавливаемое по умолчанию при создании объекта

Класс AlertType 133

класса Al ert. Может также возвратить значение константы FOREVER, если по умол­чанию сообщение демонстрируется неограниченное количество времени;

Image getlmageO — возвращает объект картинки, установленной для сообще­ния, или значение nul 1, если картинка не установлена;

String getStringO — возвращает текст данного сообщения;

1 nt getTi meout C) — возвращает время демонстрации данного сообщения в мил­лисекундах или константу FOREVER;

Al ertType getType() — возвращает тип данного сообщения в виде объекта клас­са AlertType;

void setCommandListener(CommanciListener 1) — также.какиметодаййСоттагк!,при вызове всегда формирует исключение 111egalStateException;

void setlmage( Image img) — устанавливает новую картинку для сообщения; void setString(String str) — устанавливает текст str данному сообщению;

void setTimeoutC int time) —устанавливает новое время демонстрации сообще­ния. Время задается аргументом time в миллисекундах или константой FOREVER класса Alert для неограниченного времени демон страц ии сообщения;

void setType(AlertType type) — задает новый тип сообщения в виде объекта класса AlertType.



Класс AlertType

Класс Al ertType задает тип сообщения класса Alert. Тип сообщения определяет шаб­лон, в котором будет продемонстрировано сообщение. Константы класса Al ertType определяют следующие шаблоны сообщений:



  • ALARM — события, привязанные к определенным моментам, например напоми­
    нание о назначенной встрече;

  • CONFIRMATION — подтверждение успешных результатов действий пользователя,
    например «Сообщение отправлено»;

  • ERROR — сообщение об ошибке в результате действий пользователя, например
    «Недостаточно памяти для сохранения данных»;

  • INFO — отображение информационных сообщений;

  • WARNING — предупреждение об опасных действиях пользователя, например «Все
    данные будут уничтожены».

Класс AlertType содержит лишь два метода: конструктор, не принимающий аргументов, и метод воспроизведения звукового сигнала, связанного с типом сообщения:

ш boolean playSound (Display display) — воспроизводит звук, соответствующий данному типу сообщения. В определенных устройствах некоторые звуки мо­гут отсутствовать. Возвращает значение true, если звук был воспроизведен, И false — в противоположном случае. Метод playSound может быть вызван и без использования сообщений класса Alert, например для организации зву­ковых сигналов во время игры.

134

Глава 12. Работа над ошибками




Внешний вид и звуковой сигнал сообщений каж­дого типа зависят от конкретной модели теле­фона. Например, на телефоне Nokia сообщение информационного типа выглядит, как показано на рис. 12.4.

Класс Al ert является потомком класса Screen, то есть экраном, готовым к демонстрации. Посколь­ку смена экрана по истечении тайм-аута проис­ходит автоматически, то демонстрация сообще­ния осуществляется с помощью особого метода менеджера дисплея (объекта класса Di spl ay), ко­торый принимает объект класса Alert, а также объект следующего экрана:

■ void setCurrent (Alert alert, Displayable nextDi spl ayabl e) — устанавливает в качестве текущего экрана сообщение, представленное аргументом a l ert, и задает экран nextDi spl ay-ablе, который станет текущим после закры­тия сообщения. Объект nextDi spl ayabl e не может быть объектом класса Alert или иметь значение null.

Рассмотрим использование класса Al ert на при­
мере все той же программы калькулятора. До­
полним программу проверкой деления на ноль,
которую мы проигнорировали, из-за чего при­
ложение в такой ситуации вылетало с ошибкой.
В блоке catch перехватим исключение ошибки
Рис. 12.4. Пример информационного в арифметической операции, создадим объект
сообщения сообщения об ошибке с неограниченным време-

нем демонстрации и отобразим его, указав основ­ную форму ввода в качестве следующего демон­стрируемого экрана:

import javax.microedition. lcdui .Alert;

import javax.microedition.lcdui .AlertType;

try

switch(act[O]) {



// выполнить действие в соответствии // с символом операции case '+':

res = first + second:

break: case '-':

res " first - second:

break: case '*':


Класс AlertType

135


res = first * second;

break: case V :

res • first / second:

break; default:

// ошибка: некорректный символ операции

resForm.appendC Il legal Operation") :

// отобразить сообщение

di spl ay.setCurrent(resForm):

// выйти

return:


)

// преобразовать результат в строку и добавить в форму

resForrn.a.ppend(Cnew Integer(resU.toStnngt)):

If отобразить результат

dispiay,setCurrent(resForm);

// блок перехвата арифметического исключения } catch (ArithmeticException aexc) {

t! создать сообщение об ошибке

Alert alert = new AlertC Error", "Divide by zero".null.AlertType.ERROR):

// установить бесконечное время демонстрации

alert.setTimeout(Alert. FOREVER);

// установить сообщение в качестве текущего экрана

display.setCurrent(alert.form); •






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

После нажатия клавиши Done программа возвращает­ся к первоначальному экрану ввода. Заметим, что до­бавление и обработку этой команды мы в программе не предусматривали, она появилась в результате уста­новки объекту класса Alert бесконечного времени де­монстрации. В случае установки фиксированного вре­мени демонстрации команда Done не отображается и смена экранов происходит автоматически по истечении заданного тайм-аута.

До сих пор в примерах мы лишь перехватывали воз­можные исключения, чтобы программа компилирова­лась и не вылетала при возможных ошибках. Внима-

Рис. 12.5. Теперь при де­лении на ноль программа не падает, а сообщает, что пользователь был не прав



136 Глава 12. Работа над ошибками

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

При обработке нескольких типов исключений в одном try-блоке следует быть вни­мательными, не перехватывается ли необходимое исключение в одном из блоков catch, расположенных выше. Так, если в первом же блоке catch перехватывается исключение самого общего типа Excepti on, то до остальных блоков дело не дойдет никогда. Немного практики и терпения, и вы научитесь лавировать меж подвод­ных камней объектно-ориентированных программ, а главное, помните, что акку­ратность — главный залог успеха программиста.


Каталог: Техника -> Информационные%20технологии
Информационные%20технологии -> Методические рекомендации по построению систем защиты узлов интернет 1 требования к системе защиты узла интернет 2
Техника -> Учебная программа для специальности: 1-23 01 73 Средства массовой информации
Техника -> Ремонт китайских телефонов
Техника -> Для профилактики и лечения насморка Зачем промывать нос во время насморка?
Техника -> Учебная программа для специальности: 1-23 01 73 Средства массовой информации


Поделитесь с Вашими друзьями:
1   ...   7   8   9   10   11   12   13   14   15


База данных защищена авторским правом ©vossta.ru 2019
обратиться к администрации

    Главная страница