РЕВЬЮ 4 модуль. Програма немедленно завершится потеряв все накопленные в памяти данные
Скачать 28.9 Kb.
|
Варианты обработки ошибок? 1) Вызов System.exit(1); - програма немедленно завершится потеряв все накопленные в памяти данные; 2) Возврат в случае ошибки случайное значение например NaN; - но нужно чтобы у возвращаемого типа было свободное значение, которое можно зарзервировать под ошибку, но это не всегда возможно, например генератор слуайных чисел может сгенирировать любое число, где нам взять отдельное значение под ошибку, а если видов ошибок несколько и их нужно различать то потребуется несколько видов значений; 3) Чтобы обойти проблему с резервироанием значения под ошибку в возвращаемом типе можно пойти дальше и у метода завести вызодной параметр, специально под флаг ошибки. Или возвращать не double(как в примере), а простой объкт пару состоящий из числа результата и признака ошибки. Пример: class ResuH { double value : boolean isError; } Тогда весь диапозон типа результата будет использоваться по своему назначению. If ы для отслеживания ошибки в коде никуда не денутся. 4) Заведение отдельного поля и метода в самом классе. Т.е. после вызова метода калкулэйт(пример), чтобы узнать можно ли верить только что возвращенному результату Что такое исключение? Исключения - события, которые случаются в процессе работы программы и прерывает стандартный ход её исполнения. Программа переходит в специальный режим поиска обработчика внештатной ситуации. Такой обработчик может принять какие то действия и вернуть программу в штатный режим работы. Но если обработчика не нашлось, то JVM завершит программу, но обеспечит достаточно подробный диагностический вывод, по которому программист поймет что нужно делать. Исключения поддержаны на уровне языка Java, т.е. ключевых слов и синтаксических конструкций. Кроме того они используются на уровне виртуальной машины, которая сообщает о многих своих проблемах бросая исключения. Стэктрейс StackTrace Что такое стектрейс. Какую информацию из него можно получить? Трассировка стека трассировка стека – это список методов, которые были вызваны до момента, когда в приложении произошло исключение. Трассировка - пошаговое выполнение программы с остановками на каждой команде или строке. Стек - абстрактный тип данных, представляющий собой список элементов, организованных по принципу LIFO (англ. last in — first out, «последним пришёл — первым вышел»). Какую информацию из него можно получить? В стеке всегда метод вызвавший StackTrace, будет на позиции[2]. 0 - getStackTrace 1 - имя метода (свое имя) 2 - имя метода кто вызвал [1] 3 - имя метода кто вызвал [2] 4 - и т.д. Методы StackTrace Мы тут видим прошлое, что происходило до запуска текущего методa. методы Модификатор и Тип Метод и описание boolean equals(Object obj) Возвращает true, если указанный объект является другим StackTraceElementэкземпляром, представляющим ту же точку выполнения, что и этот экземпляр. String getClassName() Возвращает полное имя класса, содержащего точку выполнения, представленную этим элементом трассировки стека. String getFileName() Возвращает имя исходного файла, содержащего точку выполнения, представленную этим элементом трассировки стека. int getLineNumber() Возвращает номер строки исходной строки, содержащей точку выполнения, представленную этим элементом трассировки стека. String getMethodName() Возвращает имя метода, содержащего точку выполнения, представленную этим элементом трассировки стека. int hashCode() Возвращает значение хеш-кода для этого элемента трассировки стека. boolean isNativeMethod() Возвращает true, если метод, содержащий точку выполнения, представленную этим элементом трассировки стека, является собственным методом. String toString() Возвращает строковое представление этого элемента трассировки стека. java.land.Throwable объект исключения Ключевое свойство экземляра Throwable и его подклассов, возможность быть брошенными. Пример бросания исключения: throw(ключевое слово) и за ним любое выражение типа Throwable, обычно просто создется экземпляр нового исключения. У класса исключения есть конструктор принимающий строку сообщения, это сообщение поясняющее проблему будет напечатано вместе со стектрейсом. Методы в классе Throwable: String getMessage() - возвращает строку с описанием проблемы. Его задача упростить диагностику проблемы, объяснить пользователю, что произошло. Правильно включать текущее состояниие объекта и параметр метода, где все произошло. Можно добавить часть того, с чем возникли проблемы при разборе. void printStackTrace() - печатает StackTrace в стандартный поток ошибок. StackTraceElement() - возвращает StackTrace который печатается в консоли в ввиде массива java объектов. Каждый из которых содержит имя класса, имя метода, имя файла, и номер строки, т.е. StackTrace можно получить и проанализировать. Trowable getCause() - он возвращает другое исключение явившиеся причиной данного. Или null если данное исключение является первичиным и не вызвано каким то другим. Trowable getSuppressed() - возвращает одно или более исключение которое мы заглушили в процессе обработки основного исключения. Виды/Группы искоючений Группы: 1) Исключения ситуации JVM: Java.lang.Error; ошибки вирутальной машины 2) Исключения ситуации в пользовательском коде: - проверяемые (checked) java.lang.Exception - особо контролируются компилятором. Код обязательно долженобрабатывать такие ошибки. Обработчик должен быть либо в методе, либо на методе было явно написано, что может появиться исключение; - непроверяемые (unchecked) java.lang,RuntimeException - их можно бросать из любой точки программы не декларируя; Иерархия исключений? При возникновении ошибки в процессе выполнения программы исполняющая среда JVM создает объект нужного типа из иерархии исключений Java – множества возможных исключительных ситуаций, унаследованных от общего «предка» – класса Throwable. Исключительные ситуации, возникающие в программе, можно разделить на две группы: Ситуации, при которых восстановление дальнейшей нормальной работы программы невозможно Восстановление возможно. К первой группе относят ситуации, когда возникают исключения, унаследованные из класса Error. Это ошибки, возникающие при выполнении программы в результате сбоя работы JVM, переполнения памяти или сбоя системы. Обычно они свидетельствуют о серьезных проблемах, устранить которые программными средствами невозможно. Такой вид исключений в Java относится к неконтролируемым (unchecked) на стадии компиляции. OutOfMemoryError(недостаточно памяти) StackOverFlowError (переполнение стека) К этой группе также относят RuntimeException – исключения, наследники класса Exception, генерируемые JVM во время выполнения программы. Часто причиной возникновения их являются ошибки программирования. Эти исключения также являются неконтролируемыми (unchecked) на стадии компиляции, поэтому написание кода по их обработке не является обязательным. NoSuchElementException (нет такого элемента) ClassCastException (исключение приведения класса) Ко второй группе относят исключительные ситуации, предвидимые еще на стадии написания программы, и для которых должен быть написан код обработки. Такие исключения являются контролируемыми (checked). Основная часть работы разработчика на Java при работе с исключениями – обработка таких ситуаций. NoSuchFieldException (нет такого поля исключения) IOException (исключение ввода-ввывода) Исключения ситуации JVM: Java.lang.Error НАЙТИ ОТВЕТ! проверяемые (checked) java.lang.Exception непроверяемые (unchecked) java.lang,RuntimeException НАЙТИ ОТВЕТ! Как создать/бросить/поймать исключение. НАЙТИ ОТВЕТ! Подавленное исключение Собственное исключение Создание собственных исключений помогает отличать одни ошибкиот других. Исключение декларируется как обычый класс, прямо или косвенно наследующий Exception или RuntimeException. Для исключений заводят конструкторы принимающие message or/and cause. Теперь в ответ на неккоректное выражение калькулятор будет бросать исключение. Если оно непроверяемое то дополнительных слов вставлять не требуется, но если оно будет проверяемым то его нужно задекларировать на уровне метода. При наследовании или реализации интерфейса нельзя декларировать переопределенному методу больше проверяемых исключений чем указано у базового метода это нарушило бы контракт базового класса. За то контракт можно менять в другую сторону, бросать в переопределенном методе меньше исключений чем задекларировано у родителя. main может декларировать и бросать любые проверяемые исключения. Все что вылетит из него приведет к распечатке StackTrace и остановки программы. Перехват исключений try – cath try - catch - конструкци для обработки исключения; Внутри try могут встречаться исключения. Далее 1 или более блок catch(класс исключения имя переменной, куда будет сложено исключение на время обработки) {код обработчика} Если за время работу try блока исключение не вылетело, но блоки catch не исполняются. Управление передается на код после них. Если исключение случилос и выполнился catch блок, то после него будет выполнен код, который идет после блоков catch. Блоков catch может быть несколько, проверяются последовательно, выбирается тот, который с подъодящим типом исключения. Проверяются как на instanseof. в отдном catch блоке можно обрабатывать несколько типов исключения. catch(исключение1 | исключение2){}. Это удобно, когда исключения не являются подклассамидруг друга. но должны обрабатываться одинаково. После try может быть блок finally, он выполниться в любом случае, вне зависимости от того было исключени или нет. Испольнился какой то catch блок или нет. finally выполняется последним. В этом блоке обычно занимаются высвобождением рсурсов. Закрытием файлов, снятием блокировок. finally не является обработчиком исключения. Есть проблема в том, что в блоке finally, так же может вылетит исключение, которое нужно обработать. Для того, чтобы избежать некрасивого кода, был придуман try с ресурсами. Finally finally — ключевое слово для отметки начала блока кода, которой является дополнительным. Этот блок помещается после последнего блока ‘catch’. Управление обычно передаётся в блок ‘finally’ в любом случае. Конструкция try - catch - with – resource Начиная с седьмой версии Java предлагает улучшенное управление ресурсами, которые должны быть закрыты после окончания работы с ними. К таким ресурсам относятся, например, файлы потоки, соединения с базами данных и сокетами. Этой цели служит специальная языковая конструкция try-with-resources. Для того чтобы это автоматическое закрытие работало создан специальный интерфейс AutoCloseable. После ключевого слова try в круглых скобках выделяются ресурсы, с которыми будет работать этот блок. Их может быть несколько. В таком случае они перечесляютя через точку с запятой. Гарантируется что после выхода из блока все ресурсы будут освобождены. Точнее что на каждом из ресурсов будет вызван метод close. Аналогично блоку finally это случиться при любом раскладе. Было исключение или небыло. Но в отличие от finally исключение из close не перебьет собой исходное исключение, а будет добавлено в него в качестве заглушенного(.addSuppressed). Ресурс это любой объект реализующий интерфейс java.lang AutoCloseable. В этом интерфейсе всего один метод close(). Это тот метод, который нужно вызывать для освобождения ресурса. Можно свободно реализовывать этот интерфейс в своих собственных классах и тогда появится возможность использовать их в блоке try с ресурсами. Что нужно делать в блоке catсh в ответ на пойманное исключение? 1. Обладаем ли мы информацией о том, как нужно реагировать на данное исключение? Если нет, то нужно пробросить это исключение дальше к вызывающему коду. Если мы решаем пробросить то же самые исключение, то блок try-catch в этом месте программы не нужен. Пусть исключение летит до того уровня где оно может быть нормально обработано. Рекомендуется ошибку заллогировать со всем steakTreasом чтобы упростить себе в будущем разбор этой проблемы. Если что то пойдет не так. Правильное использование исключений Какие гарантии вы можете дать вызывающему Вас коду? Можете ли вы дать сильные гарантии? Т.е. обещать, что несмотря на выброс исключения, объект останется исходном корректном состоянии. В нем ничего не сломается. И этим объектом можно пользоваться дальше. Или вы можете дать слабые гарантии? Т.е. если состояние объекта и изменилось, то оно осталось корректным. И объектом можно пользоваться дальше. Возможно вы гарантируете только то, что не смотря на исключение не случилось утечек ресурсов. А объект к использованию уже не прегоден. В худшем случае вы не можете гарантировать ничего из выше перечисленного. Чем более высокие гарантии вы можете обеспечить, тем удобнее будет другим программистам пользоваться Вашим классом. К этому стоит стремиться. Гарантию отсутствия утечек можно обепечить правильным использованием блоков try-finally and try with resourse. А чтобы объект не переходил в некорректное состояние можно например валидировать все входние параметры метода. Или если в методе делается многоэтапное вычисление, то промежуточные результаты этих вычислений сохранять в локальных переменных. И только когда все вычисление успешно отработало то менять состояние объекта присваивая новые значения его полям.Второе замечание. Механизм обработки иключений try - catch следует применять для действительно исключительных ситуаций. Не нужно релизовывать обычную условную логику при помощи try catch. Во первых это менее эффективно. Порождение и обработка исключений несут не нулевые накладные расходы. Во вторых можно обработать не ту ошибку, которую вы хотели, если в try блоке происходит много всего. В чем разница между checked и unchecked исключениями Все проверяемые исключения происходят от класса Exception. Что значит “проверяемые”? Мы частично упоминали об этом в прошлой лекции: “...компилятор Java знает о самых распространенных исключениях, и знает, в каких ситуациях они могут возникнуть”. Например, он знает, что если программист в коде считывает данные из файла, может легко возникнуть ситуация, что файл не существует. И таких ситуаций, которые он может заранее предположить, очень много. Поэтому компилятор заранее проверяет наш код на наличие потенциальных исключений. Если он их найдет, то не скомпилирует код, пока мы не обработаем их или не пробросим наверх. Второй вид исключений — “непроверяемые”. Они происходят от класса RuntimeException. Чем же они отличаются от проверяемых? Казалось бы, тоже есть куча разных классов, которые происходят от RuntimeException и описывают конкретные runtime-исключения. Разница в том, что этих ошибок компилятор не ожидает. Он как бы говорит: “На момент написания кода я ничего подозрительного не обнаружил, но при его работе что-то пошло не так. Видимо, в коде есть ошибки!” И это действительно так. Непроверяемые исключения чаще всего являются следствием ошибок программиста. Валидировать НАЙТИ ОТВЕТ! Что такое логгирование и для чего используется? Логирование — это процесс записи информации о событиях, происходящих в рамках какого-либо процесса с некоторым объектом. Запись может проводиться в файл регистрации или в базу данных Зачем нужно? 1) Точечная настройка логиорвания, вкючение и отключение на уровне отдельных пакетов или классов; 2) Настройку уровня детальности логирования; 3) Настройка места куда логи будут писаться; 4) Настройка формата, в котором эти логи будут вестись; Это может удобно настраиваться в конфигурационном файле. Т.е. запустили программу с одними параметрами, получили полный отладочный протокол всего что внутри программы происходило, запустили программу с другими параметрами - получили режим промышленной эксплуатации, в котором программа залогировала сначала какую то важную информацию, а потом не пишет ничего пока все идет нормально. java.util.logging Основной класс Logger - через него наша программа будет писать логги. Логги можно получить вызвав статический метод getLogger() - этот метод возвращает нам логгер с указанным именем. Обычная практика в каждом классе где требуется логгирование завести финальное статическое поле куда положить логгер с именем соответствующим полному имени класса. Как залогировать сообщение? У логгера есть метод с имемем log. Первым параметром этод метод принимает Level(уровень логгирования) - это степень серьезности данного сообщения. К примеру INFO - это информациооное сообщение о нормальном ходе исполнения програмы. Есть два более серьезных уровня и 4 менее серьезных. Для удобства на каждый уровень логгирования у логгера есть одноименный метод пример: warning - он выбрасывает сообщения сообщения соответствующего уровня. Логгер можно сконфигурировать таким образом, чтобы он игнорировал все сообщения ниже заданного. Например логгер настроенный на уровень warning, будет принимать только сообщения с уровнем SEVERE AND WARNING, и тихонько отправлять в дев нул все остальное. Настройка делается либо в коде при помощи вызова метода .setLevel(Level.WARNING), либо в конфигурационном файле. Логирование с динамической информацией Часто нужно залогировать не просто какую то статическу строчку, а добавить туда какую то динамическую информацию например значение параметров метода или текущее состояние объекта. Это можно сделать двумя способами: 1) Конкатинировать все что нам нужно в строку и передать результат в метод лог. У этого подхода есть недостаток проявляющий себя в программах работающих под большой нагрузкой, даже если логгирование данного уровня отключено все равно программа будет постоянно заниматься конкатинацией строк и тратить на это заметное время; 2) Передавать в метод лог фиксированную строку, в которой специальным образом обозначены места для подстановки и отдельно передавать значения которые будут туда подставляться. Если значение одно, то оно передается туда непосредственно. А если их несколько то нужно завернуть их в массив Object[] {}. Подстановка параметров в строку происходит внутри логгера и только при условии, что указанный уровень логгирования включен. Т.е. строчка действительно попадет в лог и не будет выкинута. Отдельно поддержан случай когда требуется получить в логгер распечатку стектрейс исключения, для этого достаточно передать в лог исключение 3 параметром. Символы подстановки при этом в сообщении не нужны. В логгер передаются только константные строки с местами для подстановки позволяет делать локализацию, т.е. перевод логгируемых сообщений на любой язык. При этом логгер внутри себя будет использовать строчку как ключ для поиска перевода в словаре, такой словарь нужно будет предоставить самому. Если перевод не будет найден то переданная строчка будет использоваться как есть. Уровни логгирования SEVERE - логгируются серьезные ошибки программы; WARNING - логгируются предупреждения; CONFIG - предназначен для логгирования конфигурационных параметров; INFO - это информациооное сообщение о нормальном ходе исполнения програмы; FINE, FINER, FINEST - для совсем детального логгирования что программа делает. Обработка решений логгирования java.util.logging.Handler Обработка решений логгирования - объект Hendler Hendler - абстрактный класс, у которого в стандартной библиотеке есть 3 наследника: 1) ConsoleHandler - выводящий сообщения в консоль ; 2) FileHandler - логгирубщий файл ; 3) SocetHandler - отправляющий лог сообщения по сети ; Handler задается в конфигурации или прикрепляется к логгеру вызовом метода логгера .addHandler(...) В каком формате сообщение записыватся в лог? java.util.logging.Formatter В каком формате сообщение записыватся в лог? За это отвечает объект Formatter. Hendler имеет ссылку на Formatter и делегирует ему всю работу по превращению залоггированного сообщения в окончательный вид пригодный к выводу в файл или передаче по сети. В стандартной библиотеке есть 2 реализации: 1) SimpleFormatter - выводящий все в более менее человекочитаемом виде; 2) XMLFormatter - производящий машиночитаемый лог в формате xml Комбинируя Logger, Handler and Firmatter можно гибко настраивать что куда и как программа будет писать. К тому же можно организовать свой собственный Handler or Formatter, если стандартный не подходит |