Что такое try catch

try-catch (Справочник по C#)

Блок try содержит защищенный код, который может вызвать исключение. Этот блок выполняется, пока не возникнет исключение или пока он не будет успешно завершен. Например, следующая попытка приведения объекта null вызывает исключение NullReferenceException:

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

Фильтры исключений предпочтительнее перехвата и повторного вызова (объясняется ниже), поскольку фильтры оставляют стек в целости и сохранности. Если последующий обработчик разгружает стек, вы можете увидеть, откуда изначально произошло исключение, а не только последнее место, в котором оно было повторно вызвано. Обычно выражения фильтра исключений используются для ведения журнала. Вы можете создать фильтр, который всегда возвращает значение false, а также записывает выходной результат в журнал, чтобы регистрировать исключения в журнале по мере их поступления без необходимости их обработки и повторного вызова.

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

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

Дополнительные сведения о перехвате исключений см. в разделе try-catch-finally.

Исключения в асинхронных методах

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

Задача может быть в состоянии сбоя, если в ожидаемом асинхронном методе произошло несколько исключений. Например, задача может быть результатом вызова метода Task.WhenAll. При ожидании такой задачи перехватывается только одно из исключений и невозможно предсказать, какое исключение будет перехвачено. См. пример в разделе Пример Task.WhenAll.

Пример

Пример двух блоков catch

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

Пример асинхронного метода

Пример Task.WhenAll

В следующем примере демонстрируется обработка исключений, когда несколько задач могут привести к нескольким исключениям. Блок try ожидает задачу, которая возвращается вызовом метода Task.WhenAll. Эта задача завершается после завершения трех задач, к которым применяется WhenAll.

Каждая из трех задач вызывает исключение. Блок catch выполняет итерацию по исключениям, которые обнаруживаются в свойстве Exception.InnerExceptions задачи, возвращенной методом Task.WhenAll.

Спецификация языка C#

Дополнительные сведения см. в разделе Оператор try в документации Спецификация C# 6.0.

Источник

try. catch

Синтаксис

Описание

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

Безусловный блок catch

Условный блок catch

Частый сценарий использования — обработать известные исключения, а при неизвестных ошибках, пробросить их дальше:

Обратите внимание: Firefox раньше поддерживал краткую запись условных блоков catch :

Однако, такой синтаксис никогда не был частью спецификации ECMAScript и был удалён из Firefox после версии 59. Сейчас он не поддерживается ни в одном браузере.

Идентификатор исключения

Блок finally

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

Другой пример: работа с файлами. В следующем фрагменте кода показывается, как скрипт открывает файл и записывает в него какие-то данные (в серверном окружении JavaScript имеет доступ к файловой системе). Во время записи может произойти ошибка. Но после открытия файл очень важно закрыть, потому что незакрытый файл может привести к утечкам памяти. В таких случаях используется блок finally :

Примеры

Вложенные блоки try

Для начала давайте посмотрим что делает этот код:

Наконец, пробросим ошибку

Возвращение значения из блока finally

Источник

Перехват ошибок, «try..catch»

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

Более новая информация по этой теме находится на странице https://learn.javascript.ru/try-catch.

Как бы мы хорошо ни программировали, в коде бывают ошибки. Или, как их иначе называют, «исключительные ситуации» (исключения).

Обычно скрипт при ошибке, как говорят, «падает», с выводом ошибки в консоль.

Но бывают случаи, когда нам хотелось бы как-то контролировать ситуацию, чтобы скрипт не просто «упал», а сделал что-то разумное.

Конструкция try…catch

При этом переменная err (можно выбрать и другое название) будет содержать объект ошибки с подробной информацией о произошедшем.

Посмотрим это на примерах.

Пример без ошибок: при запуске сработают alert (1) и (2) :

Пример с ошибкой: при запуске сработают (1) и (3) :

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

Здесь же мы рассматриваем ошибки семантические, то есть происходящие в корректном коде, в процессе выполнения.

Объект ошибки

В примере выше мы видим объект ошибки. У него есть три основных свойства:

В зависимости от браузера у него могут быть и дополнительные свойства, см. Error в MDN и Error в MSDN.

Пример использования

В JavaScript есть встроенный метод JSON.parse(str), который используется для чтения JavaScript-объектов (и не только) из строки.

Обычно он используется для того, чтобы обрабатывать данные, полученные по сети, с сервера или из другого источника.

Более детально формат JSON разобран в главе Формат JSON, метод toJSON.

В случае, если данные некорректны, JSON.parse генерирует ошибку, то есть скрипт «упадёт».

Устроит ли нас такое поведение? Конечно нет!

Получается, что если вдруг что-то не так с данными, то посетитель никогда (если, конечно, не откроет консоль) об этом не узнает.

А люди очень-очень не любят, когда что-то «просто падает», без всякого объявления об ошибке.

Бывают ситуации, когда без try..catch не обойтись, это – одна из таких.

Здесь в alert только выводится сообщение, но область применения гораздо шире: можно повторять запрос, можно предлагать посетителю использовать альтернативный способ, можно отсылать информацию об ошибке на сервер… Свобода действий.

Генерация своих ошибок

Представим на минуту, что данные являются корректным JSON… Но в этом объекте нет нужного свойства name :

Оператор throw

Оператор throw генерирует ошибку.

В качестве конструктора ошибок можно использовать встроенный конструктор: new Error(message) или любой другой.

Получилось, что блок catch – единое место для обработки ошибок во всех случаях: когда ошибка выявляется при JSON.parse или позже.

Проброс исключения

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

Конечно, может! Код – это вообще мешок с ошибками, бывает даже так, что библиотеку выкладывают в открытый доступ, она там 10 лет лежит, её смотрят миллионы людей и на 11-й год находятся опаснейшие ошибки. Такова жизнь, таковы люди.

Блок catch в нашем примере предназначен для обработки ошибок, возникающих при некорректных данных. Если же в него попала какая-то другая ошибка, то вывод сообщения о «некорректных данных» будет дезинформацией посетителя.

Ошибку, о которой catch не знает, он не должен обрабатывать.

При этом ошибка «выпадает» из try..catch наружу. Далее она может быть поймана либо внешним блоком try..catch (если есть), либо «повалит» скрипт.

В следующем примере такие ошибки обрабатываются ещё одним, «более внешним» try..catch :

Без внешнего проброшенная ошибка «вывалилась» бы в консоль с остановкой скрипта.

Оборачивание исключений

И, для полноты картины – последняя, самая продвинутая техника по работе с ошибками. Она, впрочем, является стандартной практикой во многих объектно-ориентированных языках.

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

Обычно внешний код хотел бы работать «на уровень выше», и получать либо результат, либо «ошибку чтения данных», при этом какая именно ошибка произошла – ему неважно. Ну, или, если будет важно, то хотелось бы иметь возможность это узнать, но обычно не требуется.

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

Мы его видим везде в грамотно построенном коде, но не всегда отдаём себе в этом отчёт.

Секция finally

Выглядит этот расширенный синтаксис так:

Секция finally не обязательна, но если она есть, то она выполняется всегда:

Попробуйте запустить такой код?

У него два варианта работы:

Секцию finally используют, чтобы завершить начатые операции при любом варианте развития событий.

Здесь секция finally гарантирует, что время будет подсчитано в любых ситуациях: при ошибке в sum или без неё.

Если внутри try были начаты какие-то процессы, которые нужно завершить по окончании работы, то в finally это обязательно будет сделано.

Кстати, для таких случаев иногда используют try..finally вообще без catch :

Последняя надежда: window.onerror

Допустим, ошибка произошла вне блока try..catch или выпала из try..catch наружу, во внешний код. Скрипт упал.

Можно ли как-то узнать о том, что произошло? Да, конечно.

Необходимо лишь позаботиться, чтобы функция была назначена заранее.

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

Существуют даже специальные веб-сервисы, которые предоставляют скрипты для отлова и аналитики таких ошибок, например: https://errorception.com/ или http://www.muscula.com/.

Итого

Обработка ошибок – большая и важная тема.

В JavaScript для этого предусмотрены:

Конструкция try..catch..finally – она позволяет обработать произвольные ошибки в блоке кода.

Это удобно в тех случаях, когда проще сделать действие и потом разбираться с результатом, чем долго и нудно проверять, не упадёт ли чего.

Кроме того, иногда проверить просто невозможно, например JSON.parse(str) не позволяет «проверить» формат строки перед разбором. В этом случае блок try..catch необходим.

Полный вид конструкции:

Кроме того, мы рассмотрели некоторые важные приёмы:

Оборачивание исключений – функция, в процессе работы которой возможны различные виды ошибок, может «обернуть их» в одну общую ошибку, специфичную для её задачи, и уже её пробросить дальше. Чтобы при необходимости можно было подробно определить, что произошло, исходную ошибку обычно присваивают в свойство этой, общей. Обычно это нужно для логирования.

В window.onerror можно присвоить функцию, которая выполнится при любой «выпавшей» из скрипта ошибке. Как правило, это используют в информационных целях, например отправляют информацию об ошибке на специальный сервис.

Задачи

Eval-калькулятор с ошибками

При ошибке нужно выводить сообщение и просить переввести выражение.

Вычислить любое выражение нам поможет eval :

Источник

Обработка ошибок, «try..catch»

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

Обычно скрипт в случае ошибки «падает» (сразу же останавливается), с выводом ошибки в консоль.

Синтаксис «try…catch»

Давайте рассмотрим примеры.

Пример без ошибок: выведет alert (1) и (2) :

Пример с ошибками: выведет (1) и (3) :

Чтобы try..catch работал, код должен быть выполнимым. Другими словами, это должен быть корректный JavaScript-код.

Он не сработает, если код синтаксически неверен, например, содержит несовпадающее количество фигурных скобок:

JavaScript-движок сначала читает код, а затем исполняет его. Ошибки, которые возникают во время фазы чтения, называются ошибками парсинга. Их нельзя обработать (изнутри этого кода), потому что движок не понимает код.

Таким образом, try..catch может обрабатывать только ошибки, которые возникают в корректном коде. Такие ошибки называют «ошибками во время выполнения», а иногда «исключениями».

Чтобы поймать исключение внутри запланированной функции, try..catch должен находиться внутри самой этой функции:

Объект ошибки

Когда возникает ошибка, JavaScript генерирует объект, содержащий её детали. Затем этот объект передаётся как аргумент в блок catch :

Для всех встроенных ошибок этот объект имеет два основных свойства:

В большинстве окружений доступны и другие, нестандартные свойства. Одно из самых широко используемых и поддерживаемых – это:

stack Текущий стек вызова: строка, содержащая информацию о последовательности вложенных вызовов, которые привели к ошибке. Используется в целях отладки.

Блок «catch» без переменной

Если нам не нужны детали ошибки, в catch можно её пропустить:

Использование «try…catch»

Как мы уже знаем, JavaScript поддерживает метод JSON.parse(str) для чтения JSON.

Обычно он используется для декодирования данных, полученных по сети, от сервера или из другого источника.

Мы получаем их и вызываем JSON.parse вот так:

Вы можете найти более детальную информацию о JSON в главе Формат JSON, метод toJSON.

Если json некорректен, JSON.parse генерирует ошибку, то есть скрипт «падает».

Устроит ли нас такое поведение? Конечно нет!

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

Давайте используем try..catch для обработки ошибки:

Здесь мы используем блок catch только для вывода сообщения, но мы также можем сделать гораздо больше: отправить новый сетевой запрос, предложить посетителю альтернативный способ, отослать информацию об ошибке на сервер для логирования, … Всё лучше, чем просто «падение».

Генерация собственных ошибок

Здесь JSON.parse выполнится без ошибок, но на самом деле отсутствие свойства name для нас ошибка.

Оператор «throw»

Оператор throw генерирует ошибку.

Технически в качестве объекта ошибки можно передать что угодно. Это может быть даже примитив, число или строка, но всё же лучше, чтобы это был объект, желательно со свойствами name и message (для совместимости со встроенными ошибками).

Для встроенных ошибок (не для любых объектов, только для ошибок), свойство name – это в точности имя конструктора. А свойство message берётся из аргумента.

Давайте посмотрим, какую ошибку генерирует JSON.parse :

В нашем случае отсутствие свойства name – это ошибка, ведь пользователи должны иметь имена.

Теперь блок catch становится единственным местом для обработки всех ошибок: и для JSON.parse и для других случаев.

Проброс исключения

В примере выше мы использовали try..catch для обработки некорректных данных. А что, если в блоке try <. >возникнет другая неожиданная ошибка? Например, программная (неопределённая переменная) или какая-то ещё, а не ошибка, связанная с некорректными данными.

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

К счастью, мы можем выяснить, какую ошибку мы получили, например, по её свойству name :

Есть простое правило:

Блок catch должен обрабатывать только те ошибки, которые ему известны, и «пробрасывать» все остальные.

Техника «проброс исключения» выглядит так:

В коде ниже мы используем проброс исключения, catch обрабатывает только SyntaxError :

Ошибка в строке (*) из блока catch «выпадает наружу» и может быть поймана другой внешней конструкцией try..catch (если есть), или «убьёт» скрипт.

Таким образом, блок catch фактически обрабатывает только те ошибки, с которыми он знает, как справляться, и пропускает остальные.

Пример ниже демонстрирует, как такие ошибки могут быть пойманы с помощью ещё одного уровня try..catch :

try…catch…finally

Подождите, это ещё не всё.

Если секция есть, то она выполняется в любом случае:

Расширенный синтаксис выглядит следующим образом:

Попробуйте запустить такой код:

У кода есть два пути выполнения:

Секцию finally часто используют, когда мы начали что-то делать и хотим завершить это вне зависимости от того, будет ошибка или нет.

Секция finally отлично подходит для завершения измерений несмотря ни на что.

Здесь finally гарантирует, что время будет измерено корректно в обеих ситуациях – и в случае успешного завершения fib и в случае ошибки:

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

Глобальный catch

Информация из данной секции не является частью языка JavaScript.

Существует ли способ отреагировать на такие ситуации? Мы можем захотеть залогировать ошибку, показать что-то пользователю (обычно они не видят сообщение об ошибке) и т.д.

Роль глобального обработчика window.onerror обычно заключается не в восстановлении выполнения скрипта – это скорее всего невозможно в случае программной ошибки, а в отправке сообщения об ошибке разработчикам.

Существуют также веб-сервисы, которые предоставляют логирование ошибок для таких случаев, такие как https://errorception.com или http://www.muscula.com.

Итого

Конструкция try..catch позволяет обрабатывать ошибки во время исполнения кода. Она позволяет запустить код и перехватить ошибки, которые могут в нём возникнуть.

Секций catch или finally может не быть, то есть более короткие конструкции try..catch и try..finally также корректны.

Объекты ошибок содержат следующие свойства:

Проброс исключения – это очень важный приём обработки ошибок: блок catch обычно ожидает и знает, как обработать определённый тип ошибок, поэтому он должен пробрасывать дальше ошибки, о которых он не знает.

Источник

Исключения в Java, Часть I (try-catch-finally)

Это первая часть статьи, посвященной такому языковому механизму Java как исключения (вторая (checked/unchecked) вот). Она имеет вводный характер и рассчитана на начинающих разработчиков или тех, кто только приступает к изучению языка.

Также я веду курс «Scala for Java Developers» на платформе для онлайн-образования udemy.com (аналог Coursera/EdX).

1. Ключевые слова: try, catch, finally, throw, throws

«Магия» (т.е. некоторое поведение никак не отраженное в исходном коде и потому неповторяемое пользователем) исключений #1 заключается в том, что catch, throw, throws можно использовать исключительно с java.lang.Throwable или его потомками.

throws:
Годится

catch:
Годится

throw:
Годится

Кроме того, throw требуется не-null аргумент, иначе NullPointerException в момент выполнения

throw и new — это две независимых операции. В следующем коде мы независимо создаем объект исключения и «бросаем» его

Однако, попробуйте проанализировать вот это

2. Почему используем System.err, а не System.out

System.out — buffered-поток вывода, а System.err — нет. Таким образом вывод может быть как таким

Так и вот таким (err обогнало out при выводе в консоль)

Давайте это нарисуем

когда Вы пишете в System.err — ваше сообщение тут же выводится на консоль, но когда пишете в System.out, то оно может на какое-то время быть буферизированно. Stacktrace необработанного исключение выводится через System.err, что позволяет им обгонять «обычные» сообщения.

3. Компилятор требует вернуть результат (или требует молчать)

Если в объявлении метода сказано, что он возвращает НЕ void, то компилятор зорко следит, что бы мы вернули экземпляр требуемого типа или экземпляр типа, который можно неявно привести к требуемому

вот так не пройдет (другой тип)

Вот так не выйдет — нет возврата

и вот так не пройдет (компилятор не может удостовериться, что возврат будет)

Компилятор отслеживает, что бы мы что-то вернули, так как иначе непонятно, что должна была бы напечатать данная программа

Из-забавного, можно ничего не возвращать, а «повесить метод»

Тут в d никогда ничего не будет присвоено, так как метод sqr повисает

Компилятор пропустит «вилку» (таки берем в квадрат ИЛИ висим)

Но механизм исключений позволяет НИЧЕГО НЕ ВОЗВРАЩАТЬ!

Итак, у нас есть ТРИ варианта для компилятора

Но КАКОЙ ЖЕ double вернет функция, бросающая RuntimeException?
А НИКАКОЙ!

Подытожим: бросаемое исключение — это дополнительный возвращаемый тип. Если ваш метод объявил, что возвращает double, но у вас нет double — можете бросить исключение. Если ваш метод объявил, что ничего не возвращает (void), но у вам таки есть что сказать — можете бросить исключение.

Давайте рассмотрим некоторый пример из практики.

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

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

Мы не можем ничего не вернуть

Можно, конечно, отписаться в консоль, но кто ее будет читать и как определить где была поломка. При чем, вычисление то продолжится с неправильными данными

Можно вернуть специальное значение, показывающее, что что-то не так (error code), но кто гарантирует, что его прочитают, а не просто воспользуются им?

Можем, конечно, целиком остановить виртуальную машину

Но «правильный путь» таков: если обнаружили возможное некорректное поведение, то
1. Вычисления остановить, сгенерировать сообщение-поломку, которое трудно игнорировать, предоставить пользователю информацию о причине, предоставить пользователю возможность все починить (загрузить белье назад и повторно нажать кнопку старт)

4. Нелокальная передача управления (nonlocal control transfer)

Механизм исключительных ситуация (исключений) — это механизм НЕЛОКАЛЬНОЙ ПЕРЕДАЧИ УПРАВЛЕНИЯ.
Что под этим имеется в виду?
Программа, в ходе своего выполнения (точнее исполнения инструкций в рамках отдельного потока), оперирует стеком («стопкой») фреймов. Передача управления осуществляется либо в рамках одного фрейма

и другие операторы.

return — выходим из ОДНОГО фрейма (из фрейма #4(метод h()))

throw — выходим из ВСЕХ фреймов

При помощи catch мы можем остановить летящее исключение (причина, по которой мы автоматически покидаем фреймы).
Останавливаем через 3 фрейма, пролетаем фрейм #4(метод h()) + пролетаем фрейм #3(метод g()) + фрейм #2(метод f())

Обратите внимание, стандартный сценарий работы был восстановлен в методе main() (фрейм #1)

Останавливаем через 2 фрейма, пролетаем фрейм #4(метод h()) + пролетаем фрейм #3(метод g())

Останавливаем через 1 фрейм (фактически аналог return, просто покинули фрейм «другим образом»)

Итак, давайте сведем все на одну картинку

5. try + catch (catch — полиморфен)

Напомним иерархию исключений

То, что исключения являются объектами важно для нас в двух моментах
1. Они образуют иерархию с корнем java.lang.Throwable (java.lang.Object — предок java.lang.Throwable, но Object — уже не исключение)
2. Они могут иметь поля и методы (в этой статье это не будем использовать)

По первому пункту: catch — полиморфная конструкция, т.е. catch по типу Parent перехватывает летящие экземпляры любого типа, который является Parent-ом (т.е. экземпляры непосредственно Parent-а или любого потомка Parent-а)

Даже так: в блоке catch мы будем иметь ссылку типа Exception на объект типа RuntimeException

catch по потомку не может поймать предка

catch по одному «брату» не может поймать другого «брата» (Error и Exception не находятся в отношении предок-потомок, они из параллельных веток наследования от Throwable)

По предыдущим примерам — надеюсь вы обратили внимание, что если исключение перехвачено, то JVM выполняет операторы идущие ПОСЛЕ последних скобок try+catch.
Но если не перехвачено, то мы
1. не заходим в блок catch
2. покидаем фрейм метода с летящим исключением

А что будет, если мы зашли в catch, и потом бросили исключение ИЗ catch?

В таком случае выполнение метода тоже прерывается (не печатаем «3»). Новое исключение не имеет никакого отношения к try-catch

Мы можем даже кинуть тот объект, что у нас есть «на руках»

И мы не попадем в другие секции catch, если они есть

Обратите внимание, мы не напечатали «3», хотя у нас летит Error а «ниже» расположен catch по Error. Но важный момент в том, что catch имеет отношение исключительно к try-секции, но не к другим catch-секциям.

Как покажем ниже — можно строить вложенные конструкции, но вот пример, «исправляющий» эту ситуацию

Как вы видели, мы можем расположить несколько catch после одного try.

Но есть такое правило — нельзя ставить потомка после предка! (RuntimeException после Exception)

Ставить брата после брата — можно (RuntimeException после Error)

Как происходит выбор «правильного» catch? Да очень просто — JVM идет сверху-вниз до тех пор, пока не найдет такой catch что в нем указано ваше исключение или его предок — туда и заходит. Ниже — не идет.

Выбор catch осуществляется в runtime (а не в compile-time), значит учитывается не тип ССЫЛКИ (Throwable), а тип ССЫЛАЕМОГО (Exception)

7. try + finally

finally-секция получает управление, если try-блок завершился успешно

finally-секция получает управление, даже если try-блок завершился исключением

finally-секция получает управление, даже если try-блок завершился директивой выхода из метода

finally-секция НЕ вызывается только если мы «прибили» JVM

System.exit(42) и Runtime.getRuntime().exit(42) — это синонимы

И при Runtime.getRuntime().halt(42) — тоже не успевает зайти в finally

exit() vs halt()
javadoc: java.lang.Runtime#halt(int status)
… Unlike the exit method, this method does not cause shutdown hooks to be started and does not run uninvoked finalizers if finalization-on-exit has been enabled. If the shutdown sequence has already been initiated then this method does not wait for any running shutdown hooks or finalizers to finish their work.

Однако finally-секция не может «починить» try-блок завершившийся исключение (заметьте, «more» — не выводится в консоль)

Трюк с «if (true) <. >» требуется, так как иначе компилятор обнаруживает недостижимый код (последняя строка) и отказывается его компилировать

И finally-секция не может «предотвратить» выход из метода, если try-блок вызвал return («more» — не выводится в консоль)

Однако finally-секция может «перебить» throw/return при помощи другого throw/return

finally-секция может быть использована для завершающего действия, которое гарантированно будет вызвано (даже если было брошено исключение или автор использовал return) по окончании работы

Например для освобождения захваченной блокировки

Или для закрытия открытого файлового потока

Специально для этих целей в Java 7 появилась конструкция try-with-resources, ее мы изучим позже.

Вообще говоря, в finally-секция нельзя стандартно узнать было ли исключение.
Конечно, можно постараться написать свой «велосипед»

Не рекомендуемые практики
— return из finally-секции (можем затереть исключение из try-блока)
— действия в finally-секции, которые могут бросить исключение (можем затереть исключение из try-блока)

8. try + catch + finally

Не заходим в catch, заходим в finally, продолжаем после оператора

Есть исключение и есть подходящий catch

Заходим в catch, заходим в finally, продолжаем после оператора

Есть исключение но нет подходящего catch

Не заходим в catch, заходим в finally, не продолжаем после оператора — вылетаем с неперехваченным исключением

9. Вложенные try + catch + finally

Операторы обычно допускают неограниченное вложение.
Пример с if

Суть в том, что try-cacth-finally тоже допускает неограниченное вложение.
Например вот так

Ну что же, давайте исследуем как это работает.

Вложенный try-catch-finally без исключения

Мы НЕ заходим в обе catch-секции (нет исключения), заходим в обе finally-секции и выполняем обе строки ПОСЛЕ finally.

Вложенный try-catch-finally с исключением, которое ПЕРЕХВАТИТ ВНУТРЕННИЙ catch

Мы заходим в ПЕРВУЮ catch-секцию (печатаем «3»), но НЕ заходим во ВТОРУЮ catch-секцию (НЕ печатаем «6», так как исключение УЖЕ перехвачено первым catch), заходим в обе finally-секции (печатаем «4» и «7»), в обоих случаях выполняем код после finally (печатаем «5»и «8», так как исключение остановлено еще первым catch).

Вложенный try-catch-finally с исключением, которое ПЕРЕХВАТИТ ВНЕШНИЙ catch

Мы НЕ заходим в ПЕРВУЮ catch-секцию (не печатаем «3»), но заходим в ВТОРУЮ catch-секцию (печатаем «6»), заходим в обе finally-секции (печатаем «4» и «7»), в ПЕРВОМ случае НЕ выполняем код ПОСЛЕ finally (не печатаем «5», так как исключение НЕ остановлено), во ВТОРОМ случае выполняем код после finally (печатаем «8», так как исключение остановлено).

Вложенный try-catch-finally с исключением, которое НИКТО НЕ ПЕРЕХВАТИТ

Мы НЕ заходим в ОБЕ catch-секции (не печатаем «3» и «6»), заходим в обе finally-секции (печатаем «4» и «7») и в обоих случаях НЕ выполняем код ПОСЛЕ finally (не печатаем «5» и «8», так как исключение НЕ остановлено), выполнение метода прерывается по исключению.

Контакты

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *