Причина, по которой исключения являются мощным методом отладки, заключается в том, что они отвечают на следующие три вопроса:
1. Что пошло не так?
2. Где вы совершили ошибку?
3. Почему что -то пошло не так?
В случае эффективного использования исключений тип исключения отвечает «Что» брошено, нанесение ответов на стек исключений «где» отбрасывается, информация об исключении «почему» брошено, и если ваше исключение не отвечает на все вышеперечисленные вопросы, то вы можете не использовать их хорошо.
Есть три принципа, которые могут помочь вам максимизировать использование хороших исключений во время отладки. Эти три принципа:
1. конкретный и ясный
2. Брось это рано
3. Задержка захвата
Чтобы объяснить эти три принципа эффективной обработки исключений, в этой статье обсуждается ее путем изготовления личного финансового менеджера JCheckBook, который используется для записи и отслеживания деятельности банковского счета, таких как депозиты и снятие средств и выдача счетов.
Бетон и чист
Java определяет иерархию класса исключений, которая начинается с броска, расширяет ошибку и исключение, а исключение расширяет Runtimeexception. Как показано на рисунке 1.
Эти четыре класса обобщены и не предоставляют много информации об ошибках. Хотя создание этих классов является синтаксически законным (например,: new Throwable ()), лучше относиться к ним как к виртуальным базовым классам и использовать их более специализированные подклассы. Java предоставила большое количество подклассов исключения. Если вы хотите быть более конкретным, вы также можете определить свой собственный класс исключений.
Например: пакет java.io определяет подкласс класса исключений IOException, который является более специализированным и подклассом ioException, такого как filenotfoundexception, eofexception и ObjectStreamException. Каждый описывает конкретный класс ошибок ввода/вывода: потеря файла, окончание файла исключения и сериализованные потоки объектов ошибок. Более конкретно, наша программа сможет ответить на вопрос «что пошло не так».
Также важно стараться быть максимально ясным, насколько это возможно, при ловении исключений. Например: jCheckbook может обрабатывать filenotFoundException путем повторного регистрации имени файла пользователя. Для EOFException он может продолжать работать на основе информации, прочитанной до того, как исключение будет брошено. Если objectStreamException брошено, программа должна предложить пользователю, что файл поврежден, а файл резервного копирования или другой файл следует использовать.
Java позволяет легко понять исключения, потому что мы можем определить несколько блоков улова для одного и того же блока Try, чтобы каждое исключение можно было обработать надлежащим образом отдельно.
File prefsfile = new File (prefsfilename); try {readpreferences (prefsfile);} catch (filenotfoundexception e) {// предупреждение пользователя о том, что указанный файл // не существует} catch (eofexception e) {// предупреждение пользователя, что конец файла // catch atemexexexexex e) {// warert afer what afere eleart e) {/// warer what aferme eleert e) Пользователь, который произошла какая -то другая ошибка ввода/o/o //}JCheckbook предоставляет пользователям явную информацию о захвате исключений, используя несколько блоков улова. Например: если FilenotFoundException пойман, оно может побудить пользователя указать другой файл. В некоторых случаях дополнительные усилия по кодированию, представленные несколькими блоками улова, могут быть несущественным бременем, но в этом примере дополнительный код помогает программе предоставить более удобный ответ ответ.
В дополнение к исключениям, обрабатываемым первыми тремя блоками улова, последний блок улова предоставляет пользователю более обобщенную информацию об ошибках при брошении на ioException. Таким образом, программа может как можно больше предоставить конкретную информацию, но также имеет возможность обрабатывать другие неожиданные исключения.
Иногда разработчики ловят нормализованные исключения и отображают имя класса исключений или информацию о печати для «специфичности». Не делай этого! Пользователи будут испытывать головную боль только при просмотре информации java.io.EOFException или стека, а не получение помощи. Конкретные исключения должны быть зафиксированы, и пользователь должен быть вызван «человеческими словами». Тем не менее, стек исключений может быть напечатан в вашем файле журнала. Помните, что исключения и информация о стеке используются для помощи разработчикам, а не пользователям.
Наконец, следует отметить, что jcheckbook не затрагивает исключения в readPreferences() , но оставляет исключения для улова и обработки на уровне пользовательского интерфейса, чтобы пользователи могли быть уведомлены, используя диалоговые окны или другие методы. Это называется «захват задержки», который будет обсуждаться ниже.
Выбросить рано
Информация о стеке исключений предоставляет точный порядок цепочки вызовов метода, которая приводит к возникновению исключения, включая имя класса, имя метода, имя кода и даже номер строки каждого вызова метода, чтобы точно найти сцену, где происходит исключение.
java.lang.nullpointerExceptionat java.io.fileinputstream.open (нативный метод) на java.io.fileinputstream. jcheckbook.jcheckbook.startup (jcheckbook.java:116) на jcheckbook.jcheckbook.
Выше приведен случай, когда метод Open () класса FileInputStream бросает NullPointerException. Тем не менее, обратите внимание, что FileInputStream.close() является частью стандартной библиотеки классов Java, и вполне вероятно, что проблема этого исключения заключается в том, что сам наш код не является API Java. Таким образом, проблема, вероятно, появится в одном из предыдущих методов, и, к счастью, она также напечатана в информации о стеке.
К сожалению, NullPointerException является наименее информативным (но также наиболее распространенным и сбоем) исключением в Java. Он не упоминает, что нас больше всего волнует: где ноль. Поэтому нам пришлось сделать несколько шагов назад и выяснить, где что -то пошло не так.
Пошаговая поддержание информации о стеке отслеживания и проверки кода, мы можем определить, что причиной ошибки является то, что пустой параметр файла был передан в readPreferences() . Поскольку readPreferences() знает, что он не может обрабатывать пустые имена файлов, немедленно проверьте условие:
public void readpreferences (String FileName) Throws OldalArgumentException {if (filename == null) {бросить новый allosalargumentException («filename is null»); } // if //...perform других операций ... inputstream in = new FileInputStream (имя файла); //.... Прочтите файл настройки ...} Принимая исключение на раннем этапе (также известное как «быстрое неудаче»), исключение является ясным и точным. Информация о стеке немедленно отражает то, что пошло не так (были предоставлены незаконные значения параметров), почему он пошел не так (имя файла не может быть нулевым), и где оно пошло не так (первая часть readPreferences() ). Таким образом, наша информация о стеке может быть правдиво предоставлена:
java.lang.illegalargumentException: FileName IS nullat jcheckbook.jcheckbook.readpreferences (jcheckbook.java:207) на jcheckbook.jcheckbook.startup (jcheckbook.java:116) at jcheckbook.jcheckbook. jcheckbook.jcheckbook.main (jcheckbook.java:318)
Кроме того, информация об исключении, содержащуюся в нем («Имя файла пусто») делает исключение богаче, явно отвечая на вопрос о том, что пусто, что нам не доступно в предыдущем коде.
Отказ достигается за счет немедленного исключения, когда обнаружена ошибка, ненужную конструкцию объекта или использование ресурсов, такого как файловое или сетевое соединение, можно эффективно избежать. Точно так же операции по уборке, вызванные открытием этих ресурсов, могут быть сохранены.
Задержка захвата
Одна ошибка, которую могут совершить как новички, так и мастера, - это поймать программу, прежде чем она сможет справиться с исключением. Компилятор Java косвенно облегчает это поведение, требуя, чтобы проверенное исключение было поймано или брошено. Естественный способ состоит в том, чтобы немедленно обернуть код в блоке Try и использовать Catch, чтобы уловить исключения, чтобы избежать ошибки компилятора.
Вопрос в том, что мне делать, если я получу исключение после того, как меня поймают? Худшее, что можно сделать, это ничего не делать. Пустой блок улова эквивалентен броске всего исключения в черную дыру, и вся информация, которая может объяснить, когда, где, почему ошибки неверны, будут потеряны навсегда. Немного лучше записать исключения в журнал, по крайней мере, есть записи, которые нужно проверить. Но мы не можем ожидать, что пользователи будут читать или понять файлы журналов и информацию об исключении. Также не подходит, чтобы readPreferences() отобразил диалог сообщения об ошибке, потому что, хотя jCheckbook в настоящее время является настольным приложением, мы также планируем превратить его в веб-приложение на основе HTML. В этом случае отображение диалога ошибок, очевидно, не является опцией. В то же время, независимо от версии HTML или C/S, информация о конфигурации читается на сервере, и сообщение об ошибке должно отображаться в веб -браузере или клиентской программе. readPreferences() также должен учитывать эти будущие потребности при разработке. Правильное разделение кода пользовательского интерфейса и логики программы может улучшить возможности повторного использования нашего кода.
Поймать исключение преждевременно перед условной обработкой, часто приводит к более серьезным ошибкам и другим исключениям. Например, если приведенный выше метод readPreferences() немедленно фиксирует и записывает FileNotFoundException, которое может быть выброшено при вызове конструктора FileInputStream, код станет таким:
public void readpreferences (String FileName) {// ... inputStream in = null; // не делайте этого !!! Попробуйте {in = new FileInputStream (filename);} catch (filenotFoundException e) {logger.log (e);} in.read (...); // ...}Приведенный выше код захватывает его без возможности восстановления после FilenotFoundException. Если файл не может быть найден, следующий метод, очевидно, не может его прочитать. Что произойдет, если readpreferences () попросят прочитать файл, которого не существует? Конечно, FilenotFoundException будет записано, и если мы посмотрим на файл журнала в то время, мы бы знали. Однако, что происходит, когда программа пытается прочитать данные из файла? Поскольку файл не существует, переменная в пустой, а NullpointerException будет брошено.
При отладке программы Instinct говорит нам посмотреть информацию в конце журнала. Это было бы nullpointerexception, и что очень раздражает, так это то, что это исключение очень неспецифично. Сообщение об ошибке не только вводит нас в заблуждение, что пошло не так (реальная ошибка - FilenotFoundException вместо NullPointerException), но также вводит в заблуждение источник ошибки. Реальная проблема заключается за пределами количества строк в брошенной NullPointerException, которые могут иметь несколько вызовов метода и разрушение класса. Наше внимание было привлечено к настоящей ошибке маленькой рыбой, пока мы не оглянулись на бревно, чтобы найти источник проблемы.
Поскольку то, что на самом деле следует делать readPreferences() это не поймать эти исключения, что это должно быть? Это кажется немного нелогичным, и наиболее подходящий способ - ничего не делать и не ловить исключения сразу. Оставьте ответственность перед абонентом readPreferences() и позвольте ему изучить соответствующий способ справиться с отсутствующими файлами конфигурации. Он может побудить пользователя указать другие файлы или использовать значение по умолчанию. Если это действительно не работает, это может предупредить пользователя и выйти из программы.
Способ принять ответственность за обработку исключений вверх по течению от цепочки вызовов состоит в том, чтобы объявить исключение в предложении о бросках метода. При объявлении возможных исключений, будьте осторожны, чем более конкретно, тем лучше. Это используется для определения типа исключения, который программа, вызывая ваш метод, должен знать и быть готовым к обработке. Например, версия readPreferences() «захват задержки» может выглядеть так:
public void readpreferences (String FileName) Throws OldalArgumentException, filenotFoundException, ioException {if (fileName == null) {бросить новый allosalArgumentException («имя файла NULL»); } // if // ... inputStream in = new FileInputStream (имя файла); // ...}Технически, единственное исключение, которое мы должны объявить, - это ioException, но мы явно заявляем, что этот метод может бросить FiLenotFoundException. Нелегаларгументация не требуется объявить, потому что это не проверяющее исключение (то есть подкласс runtimeexception). Тем не менее, он объявляется документировать наш код (эти исключения также должны быть помечены в Javadocs метода).
Конечно, в конечном итоге ваша программа должна поймать исключение, в противном случае она неожиданно прекратится. Но хитрость здесь состоит в том, чтобы поймать исключения на правильном уровне, чтобы ваша программа могла либо значительно восстановиться от исключений и продолжаться, не вызывая более глубокие ошибки; Или иметь возможность предоставить пользователям четкую информацию, включая их, чтобы восстановить ошибки. Если ваш метод не компетентен, не обращайтесь за исключением, оставьте его позади, чтобы поймать и обрабатывать его на правильном уровне.
Суммировать
Опытные разработчики знают, что самая большая сложность в программах отладки заключается не в том, чтобы исправить дефекты, а для выяснения укрытий дефектов из огромного количества кода. Пока вы следовали трем принципам этой статьи, ваши исключения могут помочь вам отслеживать и устранить дефекты, сделать вашу программу более надежной и удобной для пользователя. Выше приведено все содержание этой статьи, и я надеюсь, что это поможет вам в вашей учебе или на работе.