Java: Введение в ООП
Теория: Исключения
В этом уроке мы поговорим про механизм исключений. С его помощью происходит управление ошибками, которые возникают во время исполнения программы. Мы разберем концепцию проверяемых и не проверяемых исключений, научимся выбрасывать и перехватывать их.
Концепция исключений не связана с ООП, но во многих языках, включая Java, исключения завязаны на классы, поэтому эта тема рассматривается в данном курсе.
Непроверяемые исключения
Начнем с проблемы. Далеко не все ошибки можно выявить на этапе компиляции, например обращение к несуществующему индексу в массиве. Подобная ошибка возникнет уже во время работы программы и скорее всего остановит ее выполнение:
Запуск такого кода приведет к выбрасыванию (возбуждению) исключения и прерыванию работы программы. В консоли это будет выглядеть так:
Ошибка содержит не только описание того что произошло, но и указывает на то место, где она возникла включая файл и строку. Это важно для отладки.
Другая похожая ситуация – это деление на ноль. Оно тоже приводит к исключению:
Ошибки такого рода почти всегда являются багами, которые нужно исправить. В Java такие исключения называются непроверяемыми (unchecked) так как они никак специально не обрабатываются и не отслеживаются в отличие от проверяемых исключений.
Такие исключения возможны не только внутри самой Java, но и в коде библиотек и даже в коде вашего приложения. Например, если какая-то библиотека используется неправильно, внутри нее может сработать код, который выбрасывает соответствующее исключение:
Из этого кода видно, что исключение это объект. В этот объект передается сообщение об ошибке плюс в него автоматически записывается информация о том, где это исключение было выброшено. Под выбрасыванием подразумевается использование конструкции throw, а не создание объекта исключения, объект можно создать и заранее.
В данном случае используется класс RuntimeException, но так бывает не всегда. Под разные типы ошибок создаются разные исключения для удобства работы с ними, например, это помогает во время анализа текста ошибки, так как глядя на класс исключения сразу понятно о чем идет речь.
Проверяемые исключения
Проверяемые исключения – это исключения, которые могут возникнуть в любом случае, даже если в программе нет багов. Чаще всего они возникают при взаимодействии Java с внешним миром. Самое простое – это чтение файла, если файла не существует, то во время его чтения возникнет исключение.
Если мы напишем такой код, то компилятор выдаст ошибку. Он знает, что метод Files.readAllBytes() выбрасывает исключение IOException, которое является проверяемым. Такое исключение должно быть обработано, так как оно может возникнуть независимо от желания программиста. Обработка исключений делается с помощью конструкции try..catch.
Блок catch перехватывает исключение, которое было выброшено в блоке try. Само исключение попадает в catch как объект e, который можно при необходимости использовать. Вся остальная обработка лежит на плечах программиста, вплоть до того, что внутри catch может быть выброшено какое-то другое исключение, но это уже продвинутая техника, обычно используемая в библиотеках.
Перехват исключения позволяет программе продолжить работать дальше без остановки. Код после конструкции try..catch продолжит выполнение как ни в чем не бывало.
В примере выше мы обрабатываем исключение в том же месте где оно и произошло, но в реальности, ошибки обычно происходят не там, где они могут быть обработаны. Более того, сам механизм исключений появился именно по этой причине. В коде реальных проектов десятки, сотни и миллионы строк кода. Такой код разбит на множество слоев, в которых один метод вызывает другой, этот вызывает третий и так далее, подобные цепочки могут достигать сотни методов в глубину вызовов. Здесь проявляется то, что код, который вызывается на нижнем уровне, может не знать как конкретно нужно обработать возникшее исключение. Представьте себе библиотеку, которая умеет скачивать файлы по сети. Эта библиотека может использоваться в совершенно разных приложениях, которые по-разному показывают ошибки загрузки.
Похожую ситуацию мы можем имитировать и в нашем примере, если вынесем код чтения файла в отдельный метод:
Этот код не пройдет компиляцию, так как исключение IOException является проверяемым (checked), но в методе Application.readFile() нет его обработки, как того требуют проверяемые исключения. В этом месте возникает противоречие. Мы не хотим обрабатывать исключение, так как обработка будет где-то дальше, в нашем случае в методе Application.main(). Java разрешает такие ситуации через указание того, что метод выбрасывает проверяемое исключение. Определение Application.readFile() будет выглядеть так:
Теперь любой метод, который вызывает внутри себя метод Application.readFile() должен сделать одно из двух:
- Указать через
throwsкакие проверяемые исключения могут быть выброшены внутри него. - Обработать проверяемое исключение и тогда не придется использовать
throws.
Выбор зависит от того, в каком месте мы хотим обрабатывать исключения.
Рекомендуемые программы
Завершено
0 / 11


