Читаем Java: руководство для начинающих (ЛП) полностью

Одно из главных преимуществ обработки исключений заключается в том, что она позволяет вовремя отреагировать на ошибку в программе и затем продолжить ее выполнение. В качестве примера рассмотрим еще одну программу, в которой элементы одного массива делятся на элементы другого. Если при этом происходит деление на нуль, то генерируется исключение ArithmeticException. Обработка подобного исключения заключается в том, что программа уведомляет об ошибке и затем продолжает свое выполнение. Таким образом, попытка деления на нуль не приведет к аварийному завершению программы из-за ошибки при ее выполнении. Вместо этого ошибка обрабатывается изящно, не прерывая выполнение программы. // Изящная обработка исключения и продолжение выполнения программы, class ExcDemo3 { public static void main(String args[]) { int numer[] = { 4, 8, 16, 32, 64, 128 }; int denom[] = { 2, 0, 4, 4, 0, 8 }; for(int i=0; i

Результат выполнения данной программы выглядит следующим образом: 4 / 2 is 2 Can't divide by Zero! 16/ 4 is 4 32 / 4 is 8 Can't divide by Zero! 128 / 8 is 16

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

Как пояснялось ранее, с блоком try можно связать несколько операторов catch. Обычно разработчики так и поступают на практике. Каждый из операторов catch должен перехватывать отдельный тип исключений. Например, в приведенной ниже программе обрабатываются как исключения, связанные с обращением за границы массива, так и ошибки деления на нуль. // Применение нескольких операторов catch. ' class ExcDemo4 { public static void main(String args[]) { // Здесь массив numer длиннее массива denom. int numer[] = { 4, 8, 16, 32, 64, 128, 256, 512 }; int denom[] = { 2, 0, 4, 4, 0, 8 }; for(int i=0; i

Выполнение этой программы дает следующий результат: 4 / 2 is 2 Can't divide by Zero! 16 / 4 is 4 32 / 4 is 8 Can't divide by Zero! 128 / 8 is 16 No matching element found. No matching element found.

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

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

подклассами В отношении подклассов следует отметить еще одну интересную особенность применения нескольких операторов catch: условие перехвата исключений для суперкласса будет справедливо и для любых его подклассов. Например, класс Throwable является суперклассом для всех исключений, поэтому для перехвата всех возможных исключений в операторах catch следует указывать тип Throwable. Если же требуется перехватывать исключения типа суперкласса и типа подкласса, то в блоке операторов первым должен быть указан тип исключения, генерируемого подклассом. В противном случае вместе с исключением типа суперкласса будут перехвачены и все исключения производных от него классов. Это правило соблюдается автоматически, и если указать первым тип исключения, генерируемого суперклассом, то будет создан недостижимый код, поскольку условие перехвата исключения, генерируемого подклассом, никогда не будет выполнено. А ведь недостижимый код в Java считается ошибкой.

Рассмотрим в качестве примера следующую программу //В операторах catch исключения типа подкласса должны // предшествовать исключениям типа суперкласса, class ExcDemo5 { public static void main(String args[]) { // Здесь массив numer длиннее массива denom. int numer[] = { 4, 8, 16, 32, 64, 128, 256, 512 }; int denom[] = { 2, 0, 4, 4, 0, 8 }; for(int i=0; icnumer.length; i++) { try { System.out.println(numer[i] + " / " + denom[i] + " is " + numer[i]/denom[i]); } // Перехват исключения от подкласса. catch (ArraylndexOutOfBoundsException exc) { System.out.println("No matching element found."); } // Перехват исключения от суперкласса. catch (Throwable exc) { System.out.println("Some exception occurred."); } } } }

Ниже приведен результат выполнения данной программы. 4 / 2 is 2 Some exception occurred. 16 / 4 is 4 32 / 4 is 8 Some exception occurred. 128 / 8 is 16 No matching element found. No matching element found.

В данном случае оператор catch (Throwable) перехватывает все исключения, кроме ArraylndexOutOfBoundsException. Соблюдение правильного порядка следования операторов catch приобретает особое значение в том случае, когда исключения генерируются в самой программе. Вложенные блоки try

Блоки try могут быть вложенными друг в друга. Исключение, возникшее во внутреннем блоке try и не перехваченное связанным с ним блоком catch, распростра¬няется далее во внешний блок try и обрабатывается связанным с ним блоком catch. Такой порядок обработки исключений демонстрируется в приведенном ниже примере программы, где исключение ArraylndexOutOfBoundsException не перехватывается во внутреннем блоке catch, но обрабатывается во внешнем. // Применение вложенных блоков try. class NestTrys { public static void main(String args[]) { // Массив numer длиннее, чем массив denom. int numer[] = { 4, 8, 16, 32, 64, 128, 256, 512 }; int denom[] = { 2, 0, 4, 4, 0, 8 }; // Вложенные блоки try. try { // Внешний блок try. for(int i=0; i

Выполнение этой программы может дать, например, следующий результат: 4 / 2 is 2 Can't divide by Zero! 16 / 4 is 4 32 / 4 is 8 Can't divide by Zero! 128 / 8 is 16 No matching element found. Fatal error - program terminated.

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

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

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

где объект_исключения должен быть объектом класса, производного от класса Throwable.

Ниже приведен пример программы, демонстрирующий применение оператора throw. В этой программе исключение ArithmeticException генерируется вручную. // Генерирование исключения вручную, class ThrowDemo { public static void main(String args[]) { try { System.out.println("Before throw."); // Генерирование исключения. throw new ArithmeticException ; } catch (ArithmeticException exc) { // перехватить исключение System.out.println("Exception caught."); } System.out.println("After try/catch block."); } }

Выполнение этой программы дает следующий результат: Before throw. Exception caught. After try/catch block. `

Обратите внимание на то, что исключение ArithmeticException генерируется с помощью ключевого слова new в операторе throw. Дело в том, что оператор throw генерирует исключение в виде объекта. Поэтому после ключевого слова throw недостаточно указать только тип исключения, нужно еще создать объект для этой цели. Повторное генерирование исключений

Исключение, перехваченное блоком catch, может быть повторно сгенерировано для обработки другим аналогичным блоком. Чаще всего повторное генерирование исключений применяется с целью предоставить разным обработчикам доступ к исключению. Так, например, повторное генерирование имеет смысл в том случае, если один обработчик оперирует одним свойством исключения, а другой обработчик ориентирован на другое его свойство. Повторно сгенерированное исключение не может быть перехвачено тем же самым блоком catch. Оно распространяется в другие блоки catch.

Ниже приведен пример программы, демонстрирующий повторное генерирование исключений. //•Повторное генерирование исключений, class Rethrow { public static void genException { // Массив numer длиннее маесивв denom. int numer[] = { 4, 8, 16, 32, 64, 128, 256, 512 }; int denom[] = { 2, 0, 4, 4, 0, 8 }; for(int i=0; i

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

В приведенных до сих примерах программ только перехватывались исключения, но не выполнялось никаких действий над представляющими их объектами. В выражении оператора catch указываются тип исключения и параметр, принимающий объект исключения. А поскольку все исключения представлены подклассами, производными от класса Throwable, то они поддерживают методы, определенные в этом классе. Некоторые наиболее употребительные методы из класса Throwable приведены в табл. 9.1.

Таблица 9.1. Наиболее употребительные методы из класса Throwable Метод Описание Throwable filllnStackTrace Возвращает объект типа Throwable, содержащий полную трассировку стека исключений. Этот объект пригоден для повторного генерирования исключений String getLocalizedMessage Возвращает описание исключения, локализованное по региональным стандартам String getMessage Возвращает описание исключения void printStackTrace Выводит трассировку стека исключений void printStackTrace(PrintStream stream) Выводит трассировку стека исключений в указанный поток void printStackTrace(PrintWriter stream) Направляет трассировку стека исключений в указанный поток String toString Возвращает объект типа String, содержащий полное описание исключения. Этот метод вызывается из метода println при выводе объекта типа Throwable

Среди методов, определенных в классе Throwable, наибольший интерес представляют методы pr intStackTrace и toString. С помощью метода printStackTrace можно вывести стандартное сообщение об ошибке и запись последовательности вызовов методов, которые привели к возникновению исключения, А метод toString позволяет получить стандартное сообщение об ошибке. Этот метод также вызывается в том случае, когда объект исключения передается в качестве параметра методу println . Применение этих методов демонстрируется в следующем примере программы: // Применение методов из класса Throwable. class ExcTest { static void genException { int nums[] = new int[4]; System.out.println("Before exception is generated."); // сгенерировать исключение в связи с попыткой // обращения за границы массива nums[7] = 10; System.out.println("this won't be displayed"); } } class UseThrowableMethods { public static void main(String args[]) { try { ExcTest.genException ; } catch (ArraylndexOutOfBoundsException exc) { // перехватить исключение System.out.println("Standard message is: "); System.out.println(exc) ; System.out.println("\nStack trace: "); exc.printStackTrace; } System.out.println("After catch statement."); } }

Результат выполнения данной программы выглядит следующим образом: Before exception is generated. Standard message is: java.lang.ArraylndexOutOfBoundsException: 7 Stack trace: java.lang.ArraylndexOutOfBoundsException: 7 at ExcTest.genException(UseThrowableMethods.java:10) at UseThrowableMethods.main(UseThrowableMethods.java:19) After catch statement. Использование ключевого слова finally

Иногда требуется определить кодовый блок, который должен выполняться по завершении блока try/catch. Допустим, в процессе работы программы возникло исключение, требующее ее преждевременного завершения. Но в программе открыт файл или установлено сетевое соединение, а следовательно, файл нужно закрыть, а соединение разорвать. Для выполнения подобных операций нормального завершения программы удобно воспользоваться ключевым словом finally.

Для того чтобы определить код, который должен выполняться по завершении блока try/catch, нужно указать блок finally в конце последовательности операторов try/catch. Ниже приведена общая форма записи блока try/catch вместе с блоком finally. try { // Блок кода, в котором отслеживаются ошибки. } catch (тип_исключения_1 объект_исключения) { // Обработчик исключения тип_исключения_1 ) catch (тип_исключения_2 объект_исключения) { // Обработчик исключения тип_исключения_2 } //. . . finally { // Код блока finally }

Блок finally выполняется всегда по завершении блока try/catch независимо от того, какое именно условие к этому привело. Следовательно, блок finally получит управление как при нормальной работе программы, так и при возникновении ошибки. Более того, он будет вызван даже в том случае, если в блоке try или в одном из блоков catch будет присутствовать оператор return для немедленного возврата из метода.

Ниже приведен краткий пример программы, демонстрирующий применение блока finally. // Применение блока finally, class UseFinally { public static void genException(int what) { int t; int nums[] = new int[2]; System.out.println("Receiving " + what); try { switch(what) { case 0: t = 10 / what; // сгенерировать ошибку деления на нуль break; case 1: nums[4] = 4; // сгенерировать ошибку обращения к массиву break; case 2: return; // возвратиться из блока try } } catch (ArithmeticException exc) { // перехватить исключение System.out.println("Can1t divide by Zero!"); return; // возвратиться из блока catch } catch (ArraylndexOutOfBoundsException exc) { // перехватить исключение System.out.println("No matching element found."); } // Этот блок выполняется независимо от того, каким // образом завершается блок try/catch. finally { System.out.println("Leaving try."); } } } class FinallyDemo { public static void main(String args[]) { for(int i=0; i < 3; i++) { UseFinally.genException(i); System.out.println ; } } }

В результате выполнения данной программы получается следующий результат: Receiving О Can't divide by Zero! Leaving try. Receiving 1 No matching element found. Leaving try. Receiving 2 Leaving try.

Нетрудно заметить, что блок finally выполняется независимо от того, каким об¬ разом завершается блок try/catch. Использование ключевого слова throws

Иногда исключения нецелесообразно обрабатывать в том методе, в котором они возникают. В таком случае их следует указывать с помощью ключевого слова throws. Ниже приведена общая форма объявления метода, в котором присутствует ключевое слово throws. возвращаемый_тип имя_метода(список_параметров) throws список_исключений { // Тело метода }

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

Возможно, вам покажется странным, что в ряде предыдущих примеров ключевое слово throws не указывалось при генерировании исключений за пределами методов. Дело в том, что исключения, генерируемые подклассом Error или RuntimeException, можно и не указывать в списке оператора throws. Исполняющая система Java по умолчанию предполагает, что метод может их генерировать. А исключения всех остальных типов следует непременно объявить с помощью ключевого слова throws. Если этого не сделать, возникнет ошибка при компиляции.

Пример применения оператора throws уже был представлен ранее в этой книге. Напомним, что при организации ввода с клавиатуры в метод main потребовалось включить следующее выражение: throws java.io.IOException

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

Рассмотрим пример, в котором осуществляется обработка исключения IOException. В методе prompt отображается сообщение, а затем выполняется ввод символов с клавиатуры. Такой ввод данных может привести к возникновению исключения IOException. Но это исключение не обрабатывается в методе prompt . Вместо этого в объявлении метода указан оператор throws, т.е. обязанности по обработке данного исключению поручаются вызывающему методу. В данном случае вызывающим является метод main , в котором и перехватывается исключение. // Применение ключевого слова throws, class ThrowsDemo { // Обратите внимание на оператор throws в объявлении метода. public static char prompt(String str) throws java.io.IOException { System.out.print(str + ": "); return (char) System.in.read ; } public static void main(String args[]) { char ch; try { // В методе prompt может быть сгенерировано исключение, // поэтому данный метод следует вызывать в блоке try. ch = prompt("Enter a letter"); } catch(java.io.IOException exc) { System.out.println("I/O exception occurred."); ch = 'X'; } System.out.println("You pressed " + ch); } }

Обратите внимание на одну особенность приведенного выше примера. Класс IOException относится к пакету java. io. Как будет разъяснено в главе 10, в этом пакете содержатся многие языковые средства Java для организации ввода-вывода. Следовательно, пакет java.io можно импортировать, а в программе указать только имя класса IOException. Новые средства обработки исключений, внедренные в версии JDK 7

С появлением версии JDK 7 механизм обработки исключений в Java был значительно усовершенствован благодаря внедрению трех новых средств. Первое из них поддерживает автоматическое управление ресурсами, позволяющее автоматизировать процесс освобождения таких ресурсов, как файлы, когда они больше не нужны. В основу этого средства положена расширенная форма оператора try, называемая оператором try с ресурсами и описываемая в главе 10 при рассмотрении файлов. Второе новое средство называется многократным перехватом, а третье — окончательным или более точным повторным генерированием исключений. Два последних средства рассматриваются ниже.

Многократный перехват позволяет перехватывать два или более исключения одним оператором catch. Как пояснялось ранее, после оператора try можно (и даже принято) указывать два или более оператора catch. И хотя каждый блок оператора catch, как правило, содержит свою особую кодовую последовательность, нередко в двух или более блоках оператора catch выполняется одна и та же кодовая последовательность, несмотря на то, что в них перехватываются разные исключения. Вместо того чтобы перехватывать каждый тип исключения в отдельности, теперь можно воспользоваться единым блоком оператора catch для обработки исключений, не дублируя код.

Для организации многократного перехвата следует указать список исключений в одном операторе catch, разделив их типы оператором поразрядного ИЛИ. Каждый параметр многократного перехвата неявно указывается как final. (По желанию модификатор доступа final можно указать и явным образом, но это совсем не обязательно.) А поскольку каждый параметр многократного перехвата неявно указывается как final, то ему нельзя присвоить новое значение.

В приведенной ниже строке кода показывается, каким образом многократный перехват исключений ArithmeticException и ArraylndexOutOfBoundsException указывается в одном операторе catch. catch(final ArithmeticException | ArraylndexOutOfBoundsException e) {

Ниже приведен краткий пример программы, демонстрирующий применение многократного перехвата исключений. // Применение средства многократного перехвата исключений. // Примечание: для компиляции этого кода требуется JDK 7 // или более поздняя версия данного комплекта, class MultiCatch { public static void main(String args[]) { int a=88, b=0; int result; char chrs[] = { 'А', 'В', 'C' }; for(int i=0; i < 2; i++) { try { if (i == 0) // сгенерировать исключение ArithmeticException result = а / b; else // сгенерировать исключение ArraylndexOutOfBoundsException chrs[5] = 'X'; } // В этом операторе catch организуется перехват обоих исключений, catch(ArithmeticException | ArraylndexOutOfBoundsException е) { System.out.println("Exception caught: " + e); } } System.out.println("After multi-catch."); } }

В данном примере программы исключение ArithmeticException генерируется при попытке деления на нуль, а исключение ArraylndexOutOfBoundsException — при попытке обращения за границы массива chrs. Оба исключения перехватываются одним оператором catch.

Средство более точного повторного генерирования исключений ограничивает этот процесс лишь теми проверяемыми типами исключений, которые генерируются в соответствующем блоке try и не обрабатываются в предыдущем блоке оператора catch, а также относятся к подтипу или супертипу указываемого параметра. И хотя такая возможность требуется нечасто, ничто не мешает теперь воспользоваться ею в полной мере. А для организации окончательного повторного генерирования исключений параметр оператора catch должен быть, по существу, указан как final. Это означает, что ему нельзя присвоить новое значение в блоке catch. Он может быть указан как final явным образом, хотя это и не обязательно. Встроенные в Java исключения

В стандартном пакете java. lang определены некоторые классы, представляющие стандартные исключения Java. Часть из них использовалась в предыдущих примерах программ. Наиболее часто встречаются исключения из подклассов стандартного класса RuntimeException. А поскольку пакет java. lang импортируется по умолчанию во все программы на Java, то исключения, производные от класса RuntimeException, становятся доступными автоматически. Их даже обязательно включать в список оператора throws. В терминологии языка Java такие исключения называют непроверяемыми, поскольку компилятор не проверяет, обрабатываются или генерируются подобные исключения в методе. Непроверяемые исключения, определенные в пакете java.lang, приведены в табл. 9.2, тогда как в табл. 9.3 — те исключения из пакета j ava. lang, которые следует непременно включать в список оператора throws при объявлении метода, если, конечно, в методе содержатся операторы, способные генерировать эти исключения, а их обработка не предусмотрена в теле метода. Такие исключения принято называть проверяемыми. В Java предусмотрен также ряд других исключений, определения которых содержатся в различных библиотеках классов. К их числу можно отнести упоминавшееся ранее исключение IOException.

Таблица 9.2. Непроверяемые исключения, определенные в пакете java.lang Исключение Описание ArithmeticException Арифметическая ошибка, например попытка деления на нуль ArraylndexOutOfBoundsException Попытка обращения за границы массива ArrayStoreException Попытка ввести в массив элемент, несовместимый с ним по типу ClassCastException Недопустимое приведение типов EnumConstNotPresentException Попытка использования нумерованного значения, которое не было определено ранее IllegalArgumentException Недопустимый параметр при вызове метода IllegalMonitorStateException Недопустимая операция контроля, например, ожидание разблокировки потока IllegalStateException Недопустимое состояние среды выполнения или приложения IllegalThreadStateException Запрашиваемая операция несовместима с текущим состоянием потока IndexOutOfBoundsException Недопустимое значение индекса NegativeArraySizeException Создание массива отрицательного размера NullPointerException Недопустимое использование пустой ссылки NumberFormatException Неверное преобразование символьной строки в число SecurityException Попытка нарушить систему защиты StringlndexOutOfBounds Попытка обращения к символьной строке за ее границами TypeNotPresentException Неизвестный тип UnsupportedOperationException Неподдерживаемая операция

Таблица 9.3. Проверяемые исключения, определенные в пакете java.lang Исключение Описание ClassNotFoundException Класс не найден CloneNotSupportedException Попытка клонирования объекта, не реализующего интерфейс Cloneable IllegalAccessException Доступ к классу запрещен InstantiationException Попытка создания объекта абстрактного класса или интер¬фейса InterruptedException Прерывание одного потока другим NoSuchFieldException Требуемое поле не существует NoSuchMethodException Требуемый метод не существует ReflectiveOperationException Суперкласс исключений, связанных с рефлексией (добавлен в версии JDK 7) Создание подклассов, производных от класса Exception

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

В классе Exception не определены новые методы. Он лишь наследует методы, предоставляемые классом Throwable. Таким образом, все исключения, включая и создаваемые вами, содержат методы класса Throwable. Конечно же, вы вольны переопределить в создаваемом вами классе один или несколько методов.

Ниже приведен пример, в котором создается исключение NonlntResultException. Оно генерируется в том случае, если результатом деления двух целых чисел является дробное число. В классе NonlntResultException содержатся два поля, предназначенные для хранения целых чисел, а также конструктор. В нем также переопределен метод toString , что дает возможность выводить описание исключения с помощью метода println. // Применение специально создаваемого исключения. // создать исключение class NonlntResultException extends Exception { int n; int d; NonlntResultException(int i, int j) { n = i; d = j; } public String toString { return "Result of " + n + " / " + d + " is non-integer."; } } class CustomExceptDemo { public static void main(String args[]) { // В массиве numer содержатся нечетные числа, int numer[] = { 4, 8, 15, 32, 64, 127, 256, 512 }; int denom[] = { 2, 0, 4, 4, 0, 8 }; for(int i=0; i

Результат выполнения данной программы выглядит следующим образом: 4 / 2 is 2 Can't divide by Zero! Result of 15 / 4 is non-integer. 32 / 4 is 8 Can't divide by Zero! Result of 127 / 8 is non-integer. No matching element found. No matching element found.

Пример для опробования 9.1. Добавление исключений в класс очереди

В этом проекте предстоит создать два класса исключении, которые будут использоваться классом очереди, разработанным в примере для опробования 8.1. Эти исключения должны указывать на переполнение и опустошение очереди, а генерировать их будут методы put и get соответственно. Ради простоты эти исключения добавляются в класс FixedQueue, но вы можете без труда внедрить их в любые другие классы очереди, разработанные в примере для опробования 8.1.

Последовательность действий

Создайте файл QExcDemo.java.

Определите следующие исключения в файле QExcDemo.java: /* Пример для опробования 9.1. Добавление обработчиков исключений в класс очереди. */ // Исключение, указывающее на переполнение очереди, class QueueFullException extends Exception { int size; QueueFullException(int s) { size = s; } public String toString { return "\nQueue is full. Maximum size is " + size; } } // Исключение, указывающее на опустошение очереди, class QueueEmptyException extends Exception { public String toString { return "\nQueue is empty."; } }

Исключение QueueFullException генерируется при попытке поместить элемент в уже заполненную очередь, а исключение QueueEmptyException — в ответ на попытку извлечь элемент из пустой очереди.

Измените класс FixedQueue таким образом, чтобы при возникновении ошибки он генерировал исключение. Соответствующий код приведен ниже. Введите этот код в файл QExcDemo.java. // Класс, реализующий очередь фиксированного размера // для хранения символов. class FixedQueue implements ICharQ { private char q[]; // Массив для хранения элементов очереди, private int putloc, getloc; // Индексы размещения и извлечения // элементов очереди. // создать пустую очередь заданного размера public FixedQueue(int size) { q = new char[size+1]; // выделить память для очереди putloc = getloc = 0; } // поместить символ в очередь public void put(char ch) throws QueueFullException { if(putloc==q.length-1) throw new QueueFullException(q.length-1); putloc++; q[putloc] = ch; } // извлечь символ из очереди public char get throws QueueEmptyException { if(getloc == putloc) throw new QueueEmptyException; getloc++; return q[getloc]; } }

Добавление исключений в класс FixedQueue выполняется в два этапа. Сначала в определении методов get и put указывается оператор throws с типом генерируемого исключения. А затем в этих методах организуется генерирование исключений при возникновении ошибок. Используя исключения, можно организовать обработку ошибок в вызывающей части программы наиболее рациональным способом. Как вы помните, в предыдущих версиях рассматриваемой здесь программы выводились только сообщения об ошибках. А генерирование исключений является более профессиональным подходом к разработке данной программы.

Для опробования усовершенствованного класса FixedQueue введите в файл QExcDemo.java приведенный ниже исходный код класса QExcDemo. // Демонстрация исключений при обращении с очередью, class QExcDemo { public static void main(String args[]) { FixedQueue q = new FixedQueue(10); char ch; int i; try { // Переполнение очереди. for(i=0; i < 11; i++) { System.out.print("Attempting to store : " + (char) ('A' + i)); q.put((char) (fA' + i)); System.out.println(" - OK"); } System.out.println; } catch (QueueFullException exc) { System.out.println(exc); } System.out.println; try { // Попытка извлечь символ из пустой очереди. for(i=0; i < 11; i++) { System.out.print("Getting next char: "); ch = q.get; System.out.println(ch); } } catch (QueueEmptyException exc) { System.out.println(exc); } } }

Класс FixedQueue реализует интерфейс ICharQ, в котором определены методы get и put , и поэтому интерфейс ICharQ необходимо изменить таким образом, чтобы в нем отражалось наличие операторов throws. Ниже приведен видоизмененный соответственно код интерфейса ICharQ. Не забывайте о том, что он должен храниться в файле ICharQjava. // Интерфейс очереди для хранения символов с генерированием исключений, public interface ICharQ { // поместить символ в очередь void put(char ch) throws QueueFullException; // извлечь символ из очереди char get throws QueueEmptyException; }

Скомпилируйте сначала новую версию исходного файла IQChar. j ava, а затем исходный файл QExcDemo. java и запустите программу QExcDemo на выполнение. В итоге вы получите следующий результат ее выполнения: Attempting to store A - OK Attempting to store В - OK Attempting to store С - OK Attempting to store D - OK Attempting to store E - OK Attempting to store F - OK Attempting to store G - OK Attempting to store H - OK Attempting to store I - OK Attempting to store J - OK Attempting to store К Queue is full. Maximum size is 10 Getting next char: A Getting next char: В Getting next char: С Getting next char: D Getting next char: E Getting next char: F Getting next char: G Getting next char: H Getting next char: I Getting next char: J Getting next char: Queue is empty. Упражнение для самопроверки по материалу главы 9

Какой класс находится на вершине иерархии исключений?

Объясните вкратце, как пользоваться ключевыми словами try и catch?

Какая ошибка допущена в приведенном ниже фрагменте кода?// ... vals[18] = 10; catch (ArraylndexOutOfBoundsException exc) { // обработать ошибку }

Что произойдет, если исключение не будет перехвачено?

Какая ошибка допущена в приведенном ниже фрагменте кода?class A extends Exception { ... class В extends А { ... // ... try { // ... } catch (A exc) { ... } catch (В exc) { ... }

Может ли внутренний блок catch повторно генерировать исключение, которое будет обработано во внешнем блоке catch?

Блок finally — последний фрагмент кода, выполняемый перед завершением программы. Верно или неверно? Обоснуйте свой ответ.

Исключения какого типа необходимо явно объявлять с помощью оператора throws, включаемого в объявление метода?

Какая ошибка допущена в приведенном ниже фрагменте кода?class MyClass { // ... } // ... throw new MyClass ;

Отвечая на вопрос 3 упражнения для самопроверки по материалу главы 6, вы создали класс Stack. Добавьте в него специальные исключения для реагирования на попытку поместить элемент в переполненный стек и извлечь элемент из пустого стека.

Какими тремя способами можно сгенерировать исключение?

Назовите два подкласса, производных непосредственно от класса Throwable.

Что такое многократный перехват?

Следует ли перехватывать в программе исключения типа Error?

Перейти на страницу:

Похожие книги

Основы программирования в Linux
Основы программирования в Linux

В четвертом издании популярного руководства даны основы программирования в операционной системе Linux. Рассмотрены: использование библиотек C/C++ и стан­дартных средств разработки, организация системных вызовов, файловый ввод/вывод, взаимодействие процессов, программирование средствами командной оболочки, создание графических пользовательских интерфейсов с помощью инструментальных средств GTK+ или Qt, применение сокетов и др. Описана компиляция программ, их компоновка c библиотеками и работа с терминальным вводом/выводом. Даны приемы написания приложений в средах GNOME® и KDE®, хранения данных с использованием СУБД MySQL® и отладки программ. Книга хорошо структурирована, что делает обучение легким и быстрым. Для начинающих Linux-программистов

Нейл Мэтью , Ричард Стоунс , Татьяна Коротяева

ОС и Сети / Программирование / Книги по IT
97 этюдов для архитекторов программных систем
97 этюдов для архитекторов программных систем

Успешная карьера архитектора программного обеспечения требует хорошего владения как технической, так и деловой сторонами вопросов, связанных с проектированием архитектуры. В этой необычной книге ведущие архитекторы ПО со всего света обсуждают важные принципы разработки, выходящие далеко за пределы чисто технических вопросов.?Архитектор ПО выполняет роль посредника между командой разработчиков и бизнес-руководством компании, поэтому чтобы добиться успеха в этой профессии, необходимо не только овладеть различными технологиями, но и обеспечить работу над проектом в соответствии с бизнес-целями. В книге более 50 архитекторов рассказывают о том, что считают самым важным в своей работе, дают советы, как организовать общение с другими участниками проекта, как снизить сложность архитектуры, как оказывать поддержку разработчикам. Они щедро делятся множеством полезных идей и приемов, которые вынесли из своего многолетнего опыта. Авторы надеются, что книга станет источником вдохновения и руководством к действию для многих профессиональных программистов.

Билл де Ора , Майкл Хайгард , Нил Форд

Программирование, программы, базы данных / Базы данных / Программирование / Книги по IT
Программист-прагматик. Путь от подмастерья к мастеру
Программист-прагматик. Путь от подмастерья к мастеру

Находясь на переднем крае программирования, книга "Программист-прагматик. Путь от подмастерья к мастеру" абстрагируется от всевозрастающей специализации и технических тонкостей разработки программ на современном уровне, чтобы исследовать суть процесса – требования к работоспособной и поддерживаемой программе, приводящей пользователей в восторг. Книга охватывает различные темы – от личной ответственности и карьерного роста до архитектурных методик, придающих программам гибкость и простоту в адаптации и повторном использовании.Прочитав эту книгу, вы научитесь:Бороться с недостатками программного обеспечения;Избегать ловушек, связанных с дублированием знания;Создавать гибкие, динамичные и адаптируемые программы;Избегать программирования в расчете на совпадение;Защищать вашу программу при помощи контрактов, утверждений и исключений;Собирать реальные требования;Осуществлять безжалостное и эффективное тестирование;Приводить в восторг ваших пользователей;Формировать команды из программистов-прагматиков и с помощью автоматизации делать ваши разработки более точными.

А. Алексашин , Дэвид Томас , Эндрю Хант

Программирование / Книги по IT