что такое подавленные исключения java
Что такое подавленное исключение?
Комментарий (пользователь soc) в ответ на вопрос об оптимизации хвостовых опций упоминал, что Java 7 имеет новую функцию, называемую «подавленные исключения», из-за «добавления ARM» (поддержка процессоров ARM?).
Что такое «исключенное исключение» в этом контексте? В других контекстах «исключенное исключение» было бы исключением, которое было поймано, а затем проигнорировано (редко хорошая идея); это явно что-то другое.
ОТВЕТЫ
Ответ 1
Я полагаю, что комментатор ссылается на это исключение, которое игнорируется, когда оно выбрано внутри неявного блока finally try-with-resources, в контексте того, что существующее исключение выбрано из блока try :
Исключение может быть выбрано из блока кода, связанного с оператором try-with-resources. В примере writeToFileZipFileContents исключение может быть выбрано из блока try, и до двух исключений может быть выбрано из инструкции try-with-resources при попытке закрыть объекты ZipFile и BufferedWriter. Если исключение выбрано из блока try, и одно или несколько исключений выбрасываются из оператора try-with-resources, то те исключения, которые выбраны из инструкции try-with-resources, подавляются, а исключение, созданное блоком, является тем, который вызывается методом writeToFileZipFileContents. Вы можете получить эти подавленные исключения, вызвав метод Throwable.getSuppressed из исключения, созданного блоком try.
(Это цитирует раздел «Подавленные исключения» на связанной странице.)
Ответ 2
Компилятор должен определить, какой из них «действительно» бросить. Он выбирает исключение, выраженное в явном коде (код в блоке try ), а не в том, что выбрано неявным кодом (блок finally ). Поэтому исключение (исключения), которое бросается в неявный блок, подавляется (игнорируется). Это происходит только в случае нескольких исключений.
Ответ 3
До Java7; В коде есть исключения, которые были проигнорированы.
В класс Throwable в JDK 7 был добавлен новый конструктор и два новых метода. Они приведены ниже:
с помощью этого нового подхода мы также справимся с этим исключенным исключением.
В Java7 try-with-resources; исключение в AutoCloseable:: close() добавляется как исключенное исключение по умолчанию вместе с исключением try.
Также известно, что это отличается от цепочки исключений (были введены с JDK 1.4 и были предназначены для того, чтобы можно было легко отслеживать причинно-следственные связи между исключениями.)
Ответ 4
Подавленные исключения являются дополнительными исключениями, которые происходят в инструкции try-with-resources (представленный в Java 7), когда AutoCloseable ресурсы закрыты. Поскольку при закрытии ресурсов AutoCloseable могут возникать множественные исключения, дополнительные исключения исключаются из в качестве исключенных исключений.
Ответ 5
Выполнение кода ниже:
Со всеми строками вы получите: java.lang.RuntimeException: from finally!
Удаление блока finally вы получите: java.lang.RuntimeException: from catch!
Удаление блока catch вы получите:
Ответ 6
Я думаю, что это связано с «цепным средством исключения». Это повлияет на то, каким образом исключение обрабатывается этим средством по мере развития трассировки стека. Со временем исключения, которые являются частью группы связанных исключений, могут быть подавлены. Подробнее см. Throwable documentation.
Ответ 7
Возьмем очень простой пример
Я собрал большинство возможных сценариев с фрагментами кода и выводами в следующем сообщении.
Надеюсь, что это поможет.
Ответ 8
Вы также можете подавлять исключения на Java 6 (вовлеченный небольшой обман),
Я создал утилиту, которая прозрачно обрабатывает исключение исключения в Java 1.6 и Java 1.7. Вы можете найти реализацию здесь
Все, что вам нужно, это позвонить:
чтобы исключить исключение, и
чтобы получить исключенные исключения из Exception, если кто-либо еще использует Java 1.6
Обработка ошибок и исключения
Содержание
Методы обработки ошибок [ править ]
2. Коды возврата. Основная идея — в случае ошибки возвращать специальное значение, которое не может быть корректным. Например, если в методе есть операция деления, то придется проверять делитель на равенство нулю. Также проверим корректность аргументов a и b :
При вызове метода необходимо проверить возвращаемое значение:
Минусом такого подхода является необходимость проверки возвращаемого значения каждый раз при вызове метода. Кроме того, не всегда возможно определить тип ошибки.
3.Использовать флаг ошибки: при возникновении ошибки устанавливать флаг в соответствующее значение:
Минусы такого подхода аналогичны минусам использования кодов возврата.
4.Можно вызвать метод обработки ошибки и возвращать то, что вернет этот метод.
Но в таком случае не всегда возможно проверить корректность результата вызова основного метода.
5.В случае ошибки просто закрыть программу.
Это приведет к потере данных, также невозможно понять, в каком месте возникла ошибка.
Исключения [ править ]
В Java возможна обработка ошибок с помощью исключений:
Каждый раз, когда при выполнении программы происходит ошибка, создается объект-исключение, содержащий информацию об ошибке, включая её тип и состояние программы на момент возникновения ошибки. После создания исключения среда выполнения пытается найти в стеке вызовов метод, который содержит код, обрабатывающий это исключение. Поиск начинается с метода, в котором произошла ошибка, и проходит через стек в обратном порядке вызова методов. Если не было найдено ни одного подходящего обработчика, выполнение программы завершается.
Таким образом, механизм обработки исключений содержит следующие операции:
Классификация исключений [ править ]
Проверяемые исключения [ править ]
Наследники класса Exception (кроме наслеников RuntimeException ) являются проверяемыми исключениями(checked exception). Как правило, это ошибки, возникшие по вине внешних обстоятельств или пользователя приложения – неправильно указали имя файла, например. Эти исключения должны обрабатываться в ходе работы программы, поэтому компилятор проверяет наличие обработчика или явного описания тех типов исключений, которые могут быть сгенерированы некоторым методом.
Все исключения, кроме классов Error и RuntimeException и их наследников, являются проверяемыми.
Error [ править ]
Класс Error и его подклассы предназначены для системных ошибок. Свои собственные классы-наследники для Error писать (за очень редкими исключениями) не нужно. Как правило, это действительно фатальные ошибки, пытаться обработать которые довольно бессмысленно (например OutOfMemoryError ).
RuntimeException [ править ]
Обработка исключений [ править ]
Как и было сказано раньше, определение метода должно содержать список всех проверяемых исключений, которые метод может бросить. Также можно написать более общий класс, среди наследников которого есть эти исключения.
try-catch-finally [ править ]
Сразу после блока проверки следуют обработчики исключений, которые объявляются ключевым словом catch.
Обработка исключений, вызвавших завершение потока [ править ]
Информация об исключениях [ править ]
Разработка исключений [ править ]
Исключения в Java7 [ править ]
Можно объявлять несколько ресурсов, разделяя их точкой с запятой:
Компилятор Java SE 7 тщательнее анализирует перебрасываемые исключения. Рассмотрим следующий пример:
Примеры исключений [ править ]
Гарантии безопасности [ править ]
При возникновении исключительной ситуации, состояния объектов и программы могут удовлетворять некоторым условиям, которые определяются различными типами гарантий безопасности:
Если будет брошено исключение в этом классе, то тогда гарантируется, что ивариант «левая граница интервала меньше правой» сохранится, но значения left и right могли измениться.
BestProg
Содержание
Поиск на других ресурсах:
1. Типы исключений, которые поддерживаются системой обработки исключений Java
Из класса Throwable унаследованы два основных класса:
Схема верхнего уровня иерархии классов Java приведена на рисунке
Рисунок. Вершина иерархии классов исключений Java
Более подробно о работе оператора throws описывается в теме:
3. Перечень подклассов непроверяемых исключений из пакета java.lang
Среди всего разнообразия классов и интерфейсов пакет java.lang содержит мощный арсенал классов для обработки исключений. Эти классы и интерфейсы составляют основу всех программ на Java. Пакет java.lang автоматически импортируется во все программы.
Ниже приведен перечень подклассов непроверяемых исключений производными от класса RuntimeException и которые определены в пакете java.lang :
4. Проверяемые исключения из пакета java.lang
В языке Java в пакете java.lang реализован ряд проверяемых исключений. Ниже приведен их перечень:
Также, в перечень исключений оператора throws обязательно нужно включать собственноручно разработанные классы исключений для их проверки.
добавляет заданное исключение в список подавляемых исключений. Этот список связывается с вызывающим (данным) исключением. Метод используется для применения в операторе try с ресурсами.
возвращает исключение, лежащее в основе текущего исключения. Метод возвращает null в случае, если такое исключение отсутствует. Этот метод используется при создании цепочек исключений – он вызывает исключение, вызывающее текущее исключение.
возвращает локализованное описание исключения.
возвращает описание исключения.
получает подавленные исключения, связанные с вызывающим исключением, и возвращает массив, который содержит результат. Подавленные исключения генерируются в операторе try с ресурсами.
связывает входной параметр причина_исключения с вызывающим исключением, указывая его как причину этого вызывающего исключения. Возвращает ссылку на исключение. Метод используется при создании цепочек исключений.
выводит трассировку стека.
10. Метод printStackTrace() имеет еще две перегруженных реализации
устанавливает трассировку стека для заданных элементов.
В примере демонстрируется использование некоторых методов класса Throwable :
Текст программы следующий:
Объясним некоторые фрагменты кода.
Исключения
В методе, в котором происходит ошибка, создаётся и передаётся специальный объект. Метод может либо обработать исключение самостоятельно, либо пропустить его. В любом случае исключение ловится и обрабатывается. Исключение может появиться благодаря самой системе, либо вы сами можете создать его вручную. Системные исключения возникают при неправильном использовании языка Java или запрещённых приёмов доступа к системе. Ваши собственные исключения обрабатывают специфические ошибки вашей программы.
Вернёмся к примеру с делением. Деление на нуль может предотвратить проверкой соответствующего условия. Но что делать, если знаменатель оказался нулём? Возможно, в контексте вашей задачи известно, как следует поступить в такой ситуации. Но, если нулевой знаменатель возник неожиданно, деление в принципе невозможно, и тогда необходимо возбудить исключение, а не продолжать исполнение программы.
Существует пять ключевых слов, используемых в исключениях: try, catch, throw, throws, finally. Порядок обработки исключений следующий.
Операторы программы, которые вы хотите отслеживать, помещаются в блок try. Если исключение произошло, то оно создаётся и передаётся дальше. Ваш код может перехватить исключение при помощи блока catch и обработать его. Системные исключения автоматически передаются самой системой. Чтобы передать исключение вручную, используется throw. Любое исключение, созданное и передаваемое внутри метода, должно быть указано в его интерфейсе ключевым словом throws. Любой код, который следует выполнить обязательно после завершения блока try, помещается в блок finally
Схематически код выглядит так:
Существует специальный класс для исключений Trowable. В него входят два класса Exception и Error.
Класс Exception используется для обработки исключений вашей программой. Вы можете наследоваться от него для создания собственных типов исключений. Для распространённых ошибок уже существует класс RuntimeException, который может обрабатывать деление на ноль или определять ошибочную индексацию массива.
Класс Error служит для обработки ошибок в самом языке Java и на практике вам не придётся иметь с ним дело.
Прежде чем научиться обрабатывать исключения, нам (как и нормальному любопытному коту) хочется посмотреть, а что происходит, если ошибку не обработать. Давайте разделим число котов в вашей квартире на ноль, хотя мы и знаем, что котов на ноль делить нельзя!
Я поместил код в обработчик щелчка кнопки. Когда система времени выполнения Java обнаруживает попытку деления на ноль, она создаёт объект исключения и передаёт его. Да вот незадача, никто не перехватывает его, хотя это должны были сделать вы. Видя вашу бездеятельность, объект перехватывает стандартный системный обработчик Java, который отличается вредных характером. Он останавливает вашу программу и выводит сообщение об ошибке, которое можно увидеть в журнале LogCat:
Как видно, созданный объект исключения принадлежит к классу ArithmeticException, далее системный обработчик любезно вывел краткое описание ошибки и место возникновения.
Вряд ли пользователи вашей программы будут довольны, если вы так и оставите обработку ошибки системе. Если программа будет завершаться с такой ошибкой, то скорее всего вашу программу просто удалят. Посмотрим, как мы можем исправить ситуацию.
Поместим проблемный код в блок try, а в блоке catch обработаем исключение.
Теперь программа аварийно не закрывается, так как мы обрабатываем ситуацию с делением на ноль.
В данном случае мы уже знали, к какому классу принадлежит получаемая ошибка, поэтому в блоке catch сразу указали конкретный тип. Обратите внимание, что последний оператор в блоке try не срабатывает, так как ошибка происходит раньше строчкой выше. Далее выполнение передаётся в блок catch, далее выполняются следующие операторы в обычном порядке.
Операторы try и catch работают совместно в паре. Хотя возможны ситуации, когда catch может обрабатывать несколько вложенных операторов try.
Если вы хотите увидеть описание ошибки, то параметр e и поможет увидеть ёго.
По умолчанию, класс Trowable, к которому относится ArithmeticException возвращает строку, содержащую описание исключения. Но вы можете и явно указать метод e.toString.
Несколько исключений
Фрагмент кода может содержать несколько проблемных мест. Например, кроме деления на ноль, возможна ошибка индексации массива. В таком случае вам нужно создать два или более операторов catch для каждого типа исключения. Причём они проверяются по порядку. Если исключение будет обнаружено у первого блока обработки, то он будет выполнен, а остальные проверки пропускаются и выполнение программы продолжается с места, который следует за блоком try/catch.
В примере мы добавили массив с тремя элементами, но обращаемся к четвёртому элементу, так как забыли, что отсчёт у массива начинается с нуля. Если оставить значение переменной zero равным нулю, то сработает обработка первого исключения деления на ноль, и мы даже не узнаем о существовании второй ошибки. Но допустим, что в результате каких-то вычислений значение переменной стало равно единице. Тогда наше исключение ArithmeticException не сработает. Но сработает новое добавленное исключение ArrayIndexOutOfBoundsException. А дальше всё пойдёт как раньше.
Тут всегда нужно помнить одну особенность. При использовании множественных операторов catch обработчики подклассов исключений должные находиться выше, чем обработчики их суперклассов. Иначе, суперкласс будет перехватывать все исключения, имея большую область перехвата. Иными словами, Exception не должен находиться выше ArithmeticException и ArrayIndexOutOfBoundsException. К счастью, среда разработки сама замечает непорядок и предупреждает вас, что такой порядок не годится. Увидев такую ошибку, попробуйте перенести блок обработки исключений ниже.
Вложенные операторы try
Операторы try могут быть вложенными. Если вложенный оператор try не имеет своего обработчика catch для определения исключения, то идёт поиск обработчика catch у внешнего блока try и т.д. Если подходящий catch не будет найден, то исключение обработает сама система (что никуда не годится).
Оператор throw
Часть исключений может обрабатывать сама система. Но можно создать собственные исключения при помощи оператора throw. Код выглядит так:
Вам нужно создать экземпляр класса Throwable или его наследников. Получить объект класса Throwable можно в операторе catch или стандартным способом через оператор new.
Мы могли бы написать такой код для кнопки:
Мы объявили объект класса Cat, но забыли его проинициализировать, например, в onCreate(). Теперь нажатие кнопки вызовет исключение, которое обработает система, а в логах мы можем прочитать сообщение об ошибке. Возможно, вы захотите использовать другое исключение, например, throw new UnsupportedOperationException(«Котик не инициализирован»);.
В любом случае мы передали обработку ошибки системе. В реальном приложении вам нужно обработать ошибку самостоятельно.
Поток выполнения останавливается непосредственно после оператора throw и другие операторы не выполняются. При этом ищется ближайший блок try/catch соответствующего исключению типа.
Перепишем пример с обработкой ошибки.
Мы создали новый объект класса NullPointerException. Многие классы исключений кроме стандартного конструктора по умолчанию с пустыми скобками имеют второй конструктор с строковым параметром, в котором можно разместить подходящую информацию об исключении. Получить текст из него можно через метод getMessage(), что мы и сделали в блоке catch.
Теперь программа не закроется аварийно, а будет просто выводить сообщения в всплывающих Toast.
Оператор throws
Если метод может породить исключение, которое он сам не обрабатывает, он должен задать это поведение так, чтобы вызывающий его код мог позаботиться об этом исключении. Для этого к объявлению метода добавляется конструкция throws, которая перечисляет типы исключений (кроме исключений Error и RuntimeException и их подклассов).
Общая форма объявления метода с оператором throws:
В фрагменте список_исключений можно указать список исключений через запятую.
Создадим метод, который может породить исключение, но не обрабатывает его. А в щелчке кнопки вызовем его.
Если вы запустите пример, то получите ошибку. Исправим код.
Мы поместили вызов метода в блок try и вызвали блок catch с нужным типом исключения. Теперь ошибки не будет.
Оператор finally
Когда исключение передано, выполнение метода направляется по нелинейному пути. Это может стать источником проблем. Например, при входе метод открывает файл и закрывает при выходе. Чтобы закрытие файла не было пропущено из-за обработки исключения, был предложен механизм finally.
Ключевое слово finally создаёт блок кода, который будет выполнен после завершения блока try/catch, но перед кодом, следующим за ним. Блок будет выполнен, независимо от того, передано исключение или нет. Оператор finally не обязателен, однако каждый оператор try требует наличия либо catch, либо finally.
Встроенные исключения Java
Существуют несколько готовых системных исключений. Большинство из них являются подклассами типа RuntimeException и их не нужно включать в список throws. Вот небольшой список непроверяемых исключений.
Список проверяемых системных исключений, которые можно включать в список throws.
Создание собственных классов исключений
Система не может предусмотреть все исключения, иногда вам придётся создать собственный тип исключения для вашего приложения. Вам нужно наследоваться от Exception (напомню, что этот класс наследуется от Trowable) и переопределить нужные методы класса Throwable. Либо вы можете наследоваться от уже существующего типа, который наиболее близок по логике с вашим исключением.
Мы создали собственный класс HungryCatException, в методе testMethod() его возбуждаем, а по нажатию кнопки вызываем этот метод. В результате наше исключение сработает.
Создать класс исключения с конструктором, который получает аргумент-строку, также просто.
Ещё вариант. Добавим также метод toString().
Теперь класс содержит два конструктора. Во втором конструкторе используется конструктор родительского класса с аргументом String, вызываемый ключевым словом super.
Перехват произвольных исключений
Можно создать универсальный обработчик, перехватывающий любые типы исключения. Осуществляется это перехватом базового класса всех исключений Exception:
Подобная конструкция не упустит ни одного исключения, поэтому её следует размещать в самом конце списка обработчиков, во избежание блокировки следующих за ней обработчиков исключений.
Основные правила обработки исключений
Используйте исключения для того, чтобы:
Подавленные исключения в Java SE7
Я пытаюсь понять подавленные Исключения в Java SE7, я опубликовал 2 примера ниже. Они похожи. В следующем примере у меня создалось впечатление, что когда происходит новое “основное исключение”, подавленные игнорируются, поскольку экземпляр Я ожидал, что вывод будет “java.lang.RuntimeException: y”. Однако ответ таков:
java.lang.RuntimeException: y
suppressed java.lang.RuntimeException: a
Мое понимание заключалось в том, что после предложения tryWithResources “a” является основным Exc, тогда в foo() x становится основным exc, пока он получает подавление, но в catch, я думал, что y станет сольным основным exc и будет игнорировать все другие исключения, включая подавленные?
Как этот второй пример, он делает то, что я только что упомянул, он выводит java.lang.RuntimeException: c без исключенных исключений.
вывод: java.lang.RuntimeException: c
Перевод блока try-with-resources в блок try-catch-finally объясняется в JLS, здесь.
Значение базового оператора try-with-resources:
задается следующим переводом на объявление локальной переменной и утверждение try-catch-finally:
Если спецификация ресурса объявляет один ресурс, тогда ResourceSpecification_tail пусто (и попытка try-catch оператор сам по себе не является инструкцией try-with-resources).
Ваш код выше в основном переводит на что-то вроде
Это сбивает с толку, потому что оно смешивает try-with-resources с поведением маскировки исключения, которое предполагается использовать с помощью try-with-resources.
Также кажется, что вы не знаете, что означает, что исключение будет подавлено. Подавленное означает, что исключение привязано к существующему исключению, а не к тому, чтобы быть брошенным, и к прогрессу, заставляя исключение, забрасываемое в try-block, потеряться (обычный термин “замаскирован” ).
Маскировка исключений означает, что исключение, выведенное из блока finally или catch, приводит к тому, что любое исключение выбрасывается из блока try, отбрасываемого. Поскольку исключения, введенные в try-block, обычно описывают вашу ошибку, а исключения, закрытые при закрытии, обычно неинтересны, это плохо; try-with-resources были созданы, чтобы попытаться уменьшить распространенность этой проблемы.
Итак, в вашем первом примере foo вызывается на a1 внутри блока try, внутри foo исключение, выведенное внутри catch, y, маскирует исключение, созданное в блоке try foo. Затем, когда вызывается блок try-with-resources, вызывается метод close, а исключение, добавленное в close, добавляется к исключению y, которое находится в полете. Таким образом, ваши printlns показывают y, затем перебирают через подавленные исключения, прикрепленные к y.
Во втором примере c – это то, что выбрано из метода go (это одно и то же поведение маскировки, описанное выше). Исключение IOException в методе go try try было выбрано, метод close был вызван на выходе, в результате чего исключение, близкое к тому, чтобы быть добавленным в IOException как исключенное исключение, затем IOException маскируется с помощью c. Потому что замаскированный, и подавленное исключение связано с a, мы также теряем исключение. Исключение c, исключенное при закрытии, не имеет исключенных исключений, связанных с ним, поскольку оно было сгенерировано после выхода из блока try-with-resources.
Если исключение выбрано из блока try, и одно или несколько исключений выбрасываются из оператора try-with-resources, то исключения, выведенные из инструкции try-with-resources, подавляются. Вы можете получить эти подавленные исключения, вызвав метод Throwable.getSuppressed из исключения, созданного блоком try.
Итак, как и ожидалось, первый пример дает результат:
Во втором фрагменте кода также есть случай исключения исключений. Чтобы проверить, что я изменил вашу функцию как: