Дополнительные возможности ООП

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

Последнее обновление: 02.03.2024

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

Для обработки исключений применяется конструкция try..catch..finally. В блок try помещаются те действия, которые потенциально могут вызвать исключение (например, передача файла по сети, открытие файла и т.д.). Блок catch перехватывает возникшее исключение и обрабатывает его. Блок finally выполняет некоторые завершающие действия.

try {
    // код, генерирующий исключение
}
catch (e: Exception) {
    // обработка исключения
}
finally {
    // постобработка
}

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

Блок finally является необязательным, его можно опустить. Блок catch также может отсутствовать, однако обязательно должен быть блок try и как минимум один из блоков: либо catch, либо finally. Также конструкция может содержать несколько блоков catch для обработки каждого типа исключения, которое может возникнуть.

Блок catch выполняется, если только возникло исключение. Блок finally выполняется в любом случае, даже если нет исключения.

Например, при делении на ноль Kotlin генерирует исключение:

fun main() {

   try{
        val n1 = 2
        val n2 = 0
        val result = n1 / n2
        println(result)
   }
   catch(e: Exception){
       println("Exception")
   }
}

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

Exception

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

try{
	val n1 = 2
    val n2 = 0
    val result = n1 / n2
    println(result)
}
catch(e: Exception){
	println("Exception")
}
finally{
	println("Program has been finished")
}

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

Exception
Program has been finished

Информация об исключении

Базовый класс исключений - класс Exception предоставляет ряд свойств, которые позволяют получить различную информацию об исключении:

  • message: сообщение об исключении

  • stackTrace: трассировка стека исключения - набор строк, где было сгенерировано исключение

Из функций класса Exception следует выделить функцию printStackTrace(), которая выводит ту информацию, которая обычно отображается при необработанном исключении.

Применение свойств:

fun main() {

    try{
        val n1 = 2
        val n2 = 0
        val result = n1 / n2
        println(result)
    }
    catch(e: Exception){
        println(e.message)
        for(line in e.stackTrace) {
            println("at $line")
        }
    }
}

Консольный вывод программы:

/ by zero
at AppKt.main(app.kt:5)
at AppKt.main(app.kt)

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

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

try {
	val nums = arrayOf(1, 2, 3, 4)
	println(nums[6])
}
catch(e:ArrayIndexOutOfBoundsException){
	println("Out of bound of array")
}
catch (e: Exception){
	println(e.message)
}

В данном случае при доступе по недействительному индексу в массиве будет генерироваться исключение типа ArrayIndexOutOfBoundsException. С помощью блока catch(e:ArrayIndexOutOfBoundsException). Если в программе будут другие исключения, которые не представляют тип ArrayIndexOutOfBoundsException, то они будут обрабатываться вторым блоком catch, так как Exception - это общий тип, который подходит под все типы исключений. При этом стоит отметить, что в начале обрабатывается исключение более частного типа - ArrayIndexOutOfBoundsException, и только потом - более общего типа Exception.

Оператор throw

Возможно, в каких-то ситуациях мы вручную захотим генерировать исключение. Для генерации исключения применяется оператор throw, после которого указывается объект исключения

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

fun main() {

    val checkedAge1 = checkAge(5)
    val checkedAge2 = checkAge(-115)
}
fun checkAge(age: Int): Int{
    if(age < 1 || age > 110) throw  Exception("Invalid value $age. Age must be greater than 0 and less than 110")
    println("Age $age is valid")
    return age
}

После оператора throw указан объект исключения. Для определения объекта Exception применяется конструктор, который принимает в качестве параметра сообщение об исключении. В данном случае это сообщение о некорректности введенного значения.

И если при вызове функции checkAge() в нее будет передано число меньше 1 или больше 110, то будет сгенерировано исключение. Так, в данном случае консольный вывод будет следующим:

Age 5 is valid
Exception in thread "main" java.lang.Exception: Invalid value -115. Age must be greater than 0 and less than 110
	at AppKt.checkAge(app.kt:7)
	at AppKt.main(app.kt:4)
	at AppKt.main(app.kt)

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

fun main() {
    try {
        val checkedAge1 = checkAge(5)
        val checkedAge2 = checkAge(-115)
    }
    catch (e: Exception){
        println(e.message)
    }
}
fun checkAge(age: Int): Int{
    if(age < 1 || age > 110) throw  Exception("Invalid value $age. Age must be greater than 0 and less than 110")
    println("Age $age is valid")
    return age
}

Возвращение значения

Конструкция try может возвращать значение. Например:

fun main() {
    val checkedAge1 = try { checkAge(5) } catch (e: Exception) { null }
    val checkedAge2 = try { checkAge(-125) } catch (e: Exception) { null }
    println(checkedAge1)    // 5
    println(checkedAge2)    // null
}
fun checkAge(age: Int): Int{
    if(age < 1 || age > 110) throw  Exception("Invalid value $age. Age must be greater than 0 and less than 110")
    println("Age $age is valid")
    return age
}

В данном случае переменная checkedAge1 получает результат функцию checkAge(). Если же произойдет исключение, тогда переменная checkedAge1 получает то значение, которое указано в блоке catch, то есть в данном случае значение null.

При необрабходимости в блок catch можно добавить и другие выражения или возвратить другое значение:

fun main() {
    val checkedAge2 = try { checkAge(-125) } catch (e: Exception) { println(e.message); 18 }
    println(checkedAge2)
}
fun checkAge(age: Int): Int{
    if(age < 1 || age > 110) throw  Exception("Invalid value $age. Age must be greater than 0 and less than 110")
    println("Age $age is valid")
    return age
}

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

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850