Runtime exceptions java что это

Обновлено: 04.07.2024

Исключение ( exception ) — это ошибка, возникающая во время выполнения ( runtime ) программы. Исключения могут возникать во многих случаях, например: деление на нуль, нулевая ссылка, выход за границы массива, попытка открыть несуществующий файл и другие. Но это не обязательно ошибки программиста. Существуют ситуации, предусмотреть которые невозможно, например, сбой оборудования.

Если возникает ошибка, обработка которой в программе не предусмотрена, выполнение программы будет прервано в строке кода, содержащей ошибку. Такое аварийное завершение работы программы не очень хорошее решение. Рассмотрим, какие решения предлагает Java.

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

Как и всё в Java, исключения тоже представлены в виде классов. Исключение в Java - это объект класса Exception , который содержит информацию об ошибке, включая тип ошибки и состояние программы, в котором произошла ошибка. Создание объекта-исключения и передача его на выполнение называется броском исключения ( throw ). Говорят, что исключение выбрасывается в метод. По получении объекта исключения метод может обработать его или передать для обработки дальше

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

В заголовке блока catch , указывается имя класса исключения, для которого предназначен этот блок. Блок будет срабатывать только при возникновении данного исключения или исключения класса – наследника.

Имя ex в заголовке catch -блока — это произвольное имя. Оно служит для именования объекта-исключения и с его помощью можно извлечь информацию о возникшем исключении.

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

  • try — начало блока кода, который может привести к ошибке
  • catch — начало блока кода обработки исключений
  • finally — начало блока кода, которой выполняется в любом случае
  • throw — служит для генерации исключений
  • throws — обозначает, что метод может выбросить исключение

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

0
Exception in thread "main" java.lang.ArithmeticException: / by zero
at myexception.MyException.main(MyException.java:13)
в подпроцессе "main" произошло исключение класса ArithmeticException деления на нуль: "/ by zero". Исключение возникло при выполнении метода main класса MyException.

Выполним обработку исключительной ситуации – деление на нуль. Для отслеживания ошибки код, который ее вызывает, заключаем в блок try, а для обработки ошибки используем блок catch . Обработка ошибки – это просто вывод типа исключения.

0
Исключение:java.lang.ArithmeticException: / by zero
Программа завершена

Для блока try-catch может быть несколько блоков catch — каждый для своего исключения.

Пример.

Если в блоке try возникнет одна из двух исключительных ситуаций — FileNotFoundException или ArithmeticException, то она будут перехвачена и сработает соответствующий блок catch . Если возникнет какое-то другое исключение, то оно не будет перехвачено и работа программы будет аварийно завершена.

Классы исключительных ситуаций

Теперь мы знаем, как обрабатывать исключения, но возникает вопрос, какие исключения обрабатывать? Для ответа на него рассмотрим основные классы исключений

Throwable
|
+------- Error
|
+------- Exceptoin
|
+------- RunTimeExceptoin
|

Throwable — базовый класс для всех исключительных ситуаций.

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

Exception — это базовый класс для всех тех исключений, которые являются результатом проблем в программе, которые могут быть обработаны и предсказуемы.

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

Транслятор автоматически обрабатывает ошибки класса RuntimeException, поэтому в программе обрабатывать эти ошибки не нужно.

Классы Error и RuntimeException образуют группу непроверяемых исключительных ситуаций – программисту их проверять не нужно.

Вот перечень основных непроверяемых исключений класса RuntimeException

ArithmeticException

Арифметическая ошибка (например, деление на ноль)

ArrayIndexOutOfBoundsException

Индекс массива за пределами допустимых границ

ArrayStoreException

Присваивание элементу массива недопустимого значения

ClassCastException

Недопустимое приведение типов

IllegalArgumentException

Методу передан недопустимый аргумент

IndexOutOfBoundsException

Некоторый индекс находится за пределами допустимых для него границ

NegativeArraySizeException

Создание массива отрицательного размера

NullPointerException

Недопустимое использование нулевого указателя

NumberFormatException

Недопустимое преобразование текстовой строки в числовой формат

StringIndexOutOfBoundsException

Попытка индексирования вне пределов строки

UnsupportedOperationException

Все остальные классы, образованные от класса Exception , называются проверяемыми исключениями – их необходимо проверять в коде программы.

Перечень основыных проверяемых исключений:

· CloneNotSupportedException : класс, для объекта которого вызывается клонирование, не реализует интерфейс Clonable
· InterruptedException : поток прерван другим потоком
ClassNotFoundException : невозможно найти класс

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

fillInStackTrace()

возвращает объект Throwable, который содержит полную трассировку стека

getLocalizesMessage()

возвращает строку с локализованным описанием исключения

getMessage()

возвращает строку с описанием исключения

printStackTrace()

возвращает массив, содержащий трассировку стека исключения

toString()

возвращает объект класса String, содержащий описание исключения

Оператор throw

Оператор throw предназначен для явного вызова исключения в требуемом месте программы. После выполнения оператора throw последующие операторы не выполняются, и ищется ближайший блок try . catch , соответствующего типу исключения, для обработки исключения. Если подходящий блок не будет найден, то обработчик исключений остановит программу и выдаст состояние стека вызовов.

Пример.

С помощью оператора throw создаем (бросаем) исключение и затем перехватываем в блоке catch . В программе происходит ввод числа, и если число равно 0, то возникает исключение:

Будет выведено
0
Число n равно нулю
Программа завершена

Оператор throws

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

Java_Deep_7.4-5020-83cb21.jpg

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

Что называют исключением. Исключения в мире программирования

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

При этом в отличие от «человеческого мира», программное приложение должно чётко понимать, как поступать в подобной ситуации. И вот как раз для этого в Java и существует механизм исключений (exception).

Используемые ключевые слова

При обработке исключений в Java применяются следующие ключевые слова: — try – служит для определения блока кода, в котором может произойти исключение; — catch – необходим для определения блока кода, где происходит обработка исключения; — finally – применяется для определения блока кода, являющегося необязательным, однако при его наличии он выполняется в любом случае вне зависимости от результата выполнения блока try.

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

Кроме того: 1. Для возбуждения исключения используем throw. 2. Для предупреждения в сигнатуре методов о том, что метод может выбросить исключение, применяем throws.

Давайте на примере посмотрим, как используются ключевые слова в Java-программе:

Зачем нам механизм исключений?

Для понимания опять приведём пример из обычного мира. Представьте, что на какой-нибудь автодороге имеется участок с аварийным мостом, на котором ограничена грузоподъёмность. И если по такому мосту проедет грузовик со слишком большой массой, мост разрушится, а в момент этого ЧП ситуация для шофёра станет, мягко говоря, исключительной. И вот, дабы такого не произошло, дорожные службы заранее устанавливают на дороге соответствующие предупреждающие знаки. И тогда водитель, посмотрев на знак, сравнит массу своего авто со значением разрешённой грузоподъёмности и примет соответствующее решение, например, поедет по другой дороге.

То есть мы видим, что из-за правильных действий дорожной службы шоферы крупногабаритных транспортных средств: 1) получили возможность заранее изменить свой путь; 2) были предупреждены об опасности; 3) были предупреждены о невозможности проезжать по мосту при определённых условиях.

Вот как наш жизненный пример соотносится с применением исключения на Java:

1-20219-9bd18c.jpg

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

Что же, давайте ещё раз побудем дорожной службой. Чтобы установить знак, мы ведь должны знать места, где водителей ТС могут ждать различные неприятности. Это первое. Далее, нам ведь надо заготовить и установить знаки. Это второе. И, наконец, надо предусмотреть маршруты объезда, позволяющие избежать опасности.

В общем, механизм исключений в Java работает схожим образом. На стадии разработки программы мы выполняем «ограждение» опасных участков кода в отношении наших исключений, используя блок try<> . Чтобы предусмотреть запасные пути, применяем блок catch<> . Код, выполняемый в программе при любом исходе, пишем в блоке finally<> .

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

Что касается программирования на Java, то мы, когда пишем свои классы и методы, далеко не всегда можем предвидеть контекст их применения другими программистами в своих программах, а значит, не можем со стопроцентной вероятностью предвидеть правильный путь для разрешения исключительных ситуаций. Но предупредить коллег о возможной исключительной ситуации мы всё-таки должны, и это не что иное, как правило хорошего тона.

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

Предупреждаем о неприятностях

Если мы не планируем обрабатывать исключение в собственном методе, но желаем предупредить пользователей метода о возможной исключительной ситуации, мы используем, как это уже было упомянуто, ключевое слово throws. В сигнатуре метода оно означает, что при некоторых обстоятельствах метод может выбросить исключение. Это предупреждение становится частью интерфейса метода и даёт право пользователю на создание своего варианта реализации обработчика исключения.

После упоминания ключевого слова throws мы указываем тип исключения. Как правило, речь идёт о наследниках класса Exception Java. Но так как Java — это объектно-ориентированный язык программирования, все исключения представляют собой объекты.

2-20219-ee1e82.jpg

Иерархия исключений в Java

Когда возникают ошибки при выполнении программы, исполняющая среда Java Virtual Machine обеспечивает создание объекта нужного типа, используя иерархию исключений Java — речь идёт о множестве возможных исключительных ситуаций, которые унаследованы от класса Throwable — общего предка. При этом исключительные ситуации, которые возникают в программе, делят на 2 группы: 1. Ситуации, при которых восстановление нормальной дальнейшей работы невозможно. 2. Ситуации с возможностью восстановления.

К первой группе можно отнести случаи, при которых возникают исключения, которые унаследованы из класса Error. Это ошибки, возникающие во время выполнения программы при сбое работы Java Virtual Machine, переполнении памяти либо сбое системы. Как правило, такие ошибки говорят о серьёзных проблемах, устранение которых программными средствами невозможно. Данный вид исключений в Java относят к неконтролируемым исключениям на стадии компиляции (unchecked). К этой же группе относятся и исключения-наследники класса Exception, генерируемые Java Virtual Machine в процессе выполнения программы — RuntimeException. Данные исключения тоже считаются unchecked на стадии компиляции, а значит, написание кода по их обработке необязательно.

Что касается второй группы, то к ней относят ситуации, которые можно предвидеть ещё на стадии написания приложения, поэтому для них код обработки должен быть написан. Это контролируемые исключения (checked). И в большинстве случаев Java-разработчики работают именно с этими исключениями, выполняя их обработку.

Создание исключения

В процессе исполнения программы исключение генерируется Java Virtual Machine либо вручную посредством оператора throw. В таком случае в памяти происходит создание объекта исключения, выполнение основного кода прерывается, а встроенный в JVM обработчик исключений пробует найти способ обработать это самое исключение.

Обработка исключения

Обработка исключений в Java подразумевает создание блоков кода и производится в программе посредством конструкций try<>finally<> , try<>catch , try<>catch<>finally .

3-20219-4ec690.jpg

В процессе возбуждения исключения в try обработчик исключения ищется в блоке catch, который следует за try. При этом если в catch присутствует обработчик данного вида исключения, происходит передача управления ему. Если же нет, JVM осуществляет поиск обработчика данного типа исключения, используя для этого цепочку вызова методов. И так происходит до тех пор, пока не находится подходящий catch. После того, как блок catch выполнится, управление переходит в необязательный блок finally. Если подходящий блок catch найден не будет, Java Virtual Machine остановит выполнение программы, выведя стек вызовов методов под названием stack trace. Причём перед этим выполнится код блока finally при наличии такового.

Рассмотрим практический пример обработки исключений:

А теперь глянем на результаты работы метода main:

Блок finally чаще всего используют, чтобы закрыть открытые в try потоки либо освободить ресурсы. Но при написании программы уследить за закрытием всех ресурсов возможно не всегда. Чтобы облегчить жизнь разработчикам Java, была предложена конструкция try-with-resources , автоматически закрывающая ресурсы, открытые в try. Используя try-with-resources , мы можем переписать наш первый пример следующим образом:

А благодаря появившимся возможностям Java начиная с седьмой версии, мы можем ещё и объединять в одном блоке перехват разнотипных исключений, делая код компактнее и читабельнее:

Итоги

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

Основные вопросы об исключениях в Java

1.Что такое проверяемые и непроверяемые исключения? Если говорить коротко, то первые должны быть явно пойманы в теле метода либо объявлены в секции throws метода. Вторые вызываются проблемами, которые не могут быть решены. Например, это нулевой указатель или деление на ноль. Проверяемые исключения очень важны, ведь от других программистов, использующих ваш API, вы ожидаете, что они знают, как обращаться с исключениями. К примеру, наиболее часто встречаемое проверяемое исключение — IOException, непроверяемое — RuntimeException. 2.Почему переменные, определённые в try, нельзя использовать в catch либо finally? Давайте посмотрим на нижеследующий код. Обратите внимание, что строку s, которая объявлена в блоке try, нельзя применять в блоке catch. То есть данный код не скомпилируется.

А всё потому, что неизвестно, где конкретно в try могло быть вызвано исключение. Вполне вероятно, что оно было вызвано до объявления объекта. 3.Почему Integer.parseInt(null) и Double.parseDouble(null) вызывают разные исключения? Это проблема JDK. Так как они были разработаны разными людьми, то заморачиваться вам над этим не стоит:

4.Каковы основные runtime exceptions в Java? Вот лишь некоторые из них:

Их можно задействовать в операторе if, если условие не выполняется:

5.Возможно ли поймать в одном блоке catch несколько исключений? Вполне. Пока классы данных исключений можно отследить вверх по иерархии наследования классов до одного и того же суперкласса, возможно применение только этого суперкласса. 6.Способен ли конструктор вызывать исключения? Способен, ведь конструктор — это лишь особый вид метода.

7.Возможен ли вызов исключений в final? В принципе, можете сделать таким образом:

Но если желаете сохранить читабельность, объявите вложенный блок try-catch в качестве нового метода и вставьте вызов данного метода в блок finally.

Виды исключений в Java

Все исключения делятся на 4 вида, которые на самом деле являются классами, унаследованными друг от друга.

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

В оператор throw можно передать только объект класса-наследника Throwable . И хотя теоретическим можно написать код вида throw new Throwable(); — так обычно никто не делает. Главная цель существования класса Throwable — единый класс-предок для всех исключений.

Следующим классом исключений является класс Error — прямой наследник класса Throwable . Объекты типа Error (и его классов-наследников) создает Java-машина в случае каких-то серьезных проблем. Например, сбой в работе, нехватка памяти, и т.д.

Обычно вы как программист ничего не можете сделать в ситуации, когда в программе возникла ошибка типа Error : слишком серьезна такая ошибка. Все, что вы можете сделать — уведомить пользователя, что программа аварийно завершается или записать всю известную информацию об ошибке в лог программы.

Исключения типа Exception (и RuntimeException ) — это обычные ошибки, которые возникают во время работы многих методов. Цель каждого выброшенного исключения — быть захваченным тем блоком catch , который знает, что нужно сделать в этой ситуации.

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

Другими словами, если какая-то переменная оказалась равна null , метод выкинет NullPointerException , если в метод передали неверные аргументы — выкинет InvalidArgumentException , если в методе случайно было деление на ноль — ArithmeticException .

RuntimeException — это разновидность (подмножество) исключений Exception . Можно даже сказать, что RuntimeException — это облегченная версия обычных исключений ( Exception ): на такие исключения налагается меньше требований и ограничений

Об отличии Exception и RuntimeException вы узнаете дальше

2. Проверяемые исключения: throws , checked exceptions

Проверяемые исключения: throws, checked exceptions

Все исключения в Java делятся на 2 категории — проверяемые ( checked ) и непроверяемые ( unchecked ).

Все исключения, унаследованные от классов RuntimeException и Error , считаются unchecked-исключениями , все остальные — checked-исключениями .

В чем же основное отличие checked-исключений от unchecked ?

К checked-исключениям есть дополнительные требования. Звучат они примерно так.

Требование 1

Если метод выбрасывает checked-исключение , он должен содержать тип этого исключения в своем заголовке (сигнатуре метода). Чтобы все методы, которые вызывают данный метод, знали о том, что в нем может возникнуть такое «важное исключение».

Указывать checked-исключения надо после параметров метода после ключевого слова throws (не путать со throw ). Выглядит это примерно так:

checked-исключение unchecked-исключение

В примере справа наш код выкидывает unchecked-исключение — никаких дополнительных действий не нужно. В примере слева метод выкидывает checked-исключение , поэтому в сигнатуру метода добавили ключевое слово throws и указали тип исключения.

Если метод планирует выкидывать несколько checked-исключений , все их нужно указать после ключевого слова throws через запятую. Порядок неважен. Пример:

Требование 2

Если вы вызываете метод, у которого в сигнатуре прописаны checked-исключения , то вы не можете проигнорировать этот факт.

Вы должны либо перехватить все эти исключения, добавив блоки catch для каждого из них, либо добавить их в throws своего метода.

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

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

Вызов этого метода можно обработать 3 способами:

1. Не перехватываем возникающие исключения

Чаще всего это делается в случае, когда в методе не известно, как правильно обработать эту ситуацию.

Код Примечание
Вызывающий метод не перехватывает исключения и вынужден информировать о них других: добавить их себе в throws

2. Перехватывать часть исключений

Обрабатываем понятные ошибки, непонятные — прокидываем в вызывающий метод. Для этого нужно добавить их название в throws:

3. Перехватываем все исключения

Обработка исключений в Java. Краткий обзор

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

Что и как происходит, когда появляется ошибка

После создания исключения, Java Runtime Environment пытается найти обработчик исключения.

Если соответствующий обработчик исключений будет найден, то объект-исключение передаётся обработчику.

Если обработчик исключений не был найден, то программа завершает работу и печатает информации об исключении.

Основные элементы обработки исключений в Java

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

Давайте посмотрим простую программу обработки исключений в Java.

// в методе main() пробрасывается сразу несколько исключений public static void main ( String [ ] args ) throws FileNotFoundException , IOException < // в блоке try-catch перехватываются сразу несколько исключений вызовом дополнительного catch(. ) System . out . println ( "Необязательный блок, но раз уже написан, то выполнятся будет не зависимо от того было исключение или нет" ) ; // тестовый метод создания, обработки и пробрасывания исключения public static void testException ( int i ) throws FileNotFoundException , IOException < FileNotFoundException myException = new FileNotFoundException ( "число меньше 0: " + i ) ; throw new IOException ( "Число должно быть в пределах от 0 до 10" ) ;

А в консоле эта программа напишет такое:

java . io . FileNotFoundException : число меньше 0 : - 5 at ua . com . prologistic . ExceptionHandling . testException ( ExceptionHandling . java : 24 ) at ua . com . prologistic . ExceptionHandling . main ( ExceptionHandling . java : 10 ) Необязательный блок , но раз уже написан , то выполнятся будет не зависимо от того было исключение или нет Exception in thread "main" java . io . IOException : Число должно быть в пределах от 0 до 10 at ua . com . prologistic . ExceptionHandling . testException ( ExceptionHandling . java : 27 ) at ua . com . prologistic . ExceptionHandling . main ( ExceptionHandling . java : 19 )

Обратите внимание, что метод testException() бросает исключение, используя ключевое слово throw , а в сигнатуре метода используется ключевое слово throws , чтобы дать понять вызывающему методу тип исключений, которые может бросить testException() .

Важные моменты в обработке исключений:

Иерархия исключений в Java

На рисунке 1 представлена иерархия исключений в Java:

иерархия исключений в Java

Полезные методы в обработке исключений

Класс Exception и все его подклассы не содержат какие-либо методы для обработки исключений. Все предоставляемые методы находятся в базовом классе Throwable . Подклассы класса Exception созданы для того, чтобы определять различные виды исключений. Именно поэтому при обработке исключений мы можем легко определить причину и обработать исключение в соответствии с его типом.

Полезные методы класса Throwable :

Автоматическое управление ресурсами и улучшения блока перехвата ошибок в Java 7

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

Читайте также: