Учебники

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

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

Исключение широко классифицируется на следующие категории —

  • Проверенное исключение — классы, которые расширяют класс Throwable, кроме RuntimeException и Error, называются проверенными исключениями. Например, IOException, SQLException и т. Д. Проверенные исключения проверяются во время компиляции.

Проверенное исключение — классы, которые расширяют класс Throwable, кроме RuntimeException и Error, называются проверенными исключениями. Например, IOException, SQLException и т. Д. Проверенные исключения проверяются во время компиляции.

Давайте рассмотрим следующую программу, которая выполняет операцию над файлом с именем Example.txt. Однако всегда может быть случай, когда файл Example.txt не существует.

Live Demo

(ns clojure.examples.example
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (def string1 (slurp "Example.txt"))
   (println string1))
(Example)

Если файл Example.txt не существует, программа создаст следующее исключение.

Caused by: java.io.FileNotFoundException: Example.txt (No such file or
directory)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at clojure.java.io$fn__9185.invoke(io.clj:229)
at clojure.java.io$fn__9098$G__9091__9105.invoke(io.clj:69)
at clojure.java.io$fn__9197.invoke(io.clj:258)
at clojure.java.io$fn__9098$G__9091__9105.invoke(io.clj:69)

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

  • Непроверенное исключение — классы, которые расширяют RuntimeException, называются непроверенными исключениями. Например, ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException и т. Д. Непроверенные исключения не проверяются во время компиляции, а проверяются во время выполнения.

Непроверенное исключение — классы, которые расширяют RuntimeException, называются непроверенными исключениями. Например, ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException и т. Д. Непроверенные исключения не проверяются во время компиляции, а проверяются во время выполнения.

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

Live Demo

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (try
      (aget (int-array [1 2 3]) 5)
      (catch Exception e (println (str "caught exception: " (.toString e))))
      (finally (println "This is our final block")))
   (println "Let's move on"))
(Example)

Когда приведенный выше код выполняется, возникает следующее исключение.

caught exception: java.lang.ArrayIndexOutOfBoundsException: 5
This is our final block
Let's move on

ошибка

Ошибка необратима, например, OutOfMemoryError, VirtualMachineError, AssertionError и т. Д. Это ошибки, из-за которых программа никогда не сможет восстановиться и приведет к ее аварийному завершению. Теперь нам нужен механизм для перехвата этих исключений, чтобы программа могла продолжать работать, если такие исключения существуют.

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

Исключения в Clojure

Ловить исключения

Как и другие языки программирования, Clojure предоставляет обычный блок try-catch для перехвата исключений по мере их возникновения.

Ниже приведен общий синтаксис блока try-catch.

(try
   (//Protected code)
   catch Exception e1)
(//Catch block)

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

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

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

Live Demo

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (try
      (def string1 (slurp "Example.txt"))
      (println string1)
      (catch Exception e (println (str "caught exception: " (.getMessage e))))))
(Example)

Вышеуказанная программа производит следующий вывод.

caught exception: Example.txt (No such file or directory)

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

Многократные Пойманные Блоки

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

Давайте изменим наш предыдущий код, включив в него два блока catch, один из которых относится к исключению для нашего файла not found, а другой — к блоку общего исключения.

Live Demo

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (try
      (def string1 (slurp "Example.txt"))
      (println string1)
      
      (catch java.io.FileNotFoundException e (println (str "caught file
         exception: " (.getMessage e))))
      
      (catch Exception e (println (str "caught exception: " (.getMessage e)))))
   (println "Let's move on"))
(Example)

Вышеуказанная программа производит следующий вывод.

caught file exception: Example.txt (No such file or directory)
Let's move on

Из вышеприведенного вывода мы ясно видим, что наше исключение было перехвачено блоком перехвата FileNotFoundException, а не общим.

Наконец-то блок

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

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

(try
   (//Protected code)
   catch Exception e1)
(//Catch block)
(finally
   //Cleanup code)

Давайте изменим приведенный выше код и добавим блок finally. Ниже приведен фрагмент кода.

Live Demo

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (try
      (def string1 (slurp "Example.txt"))
      (println string1)
      
      (catch java.io.FileNotFoundException e (println (str "caught file
         exception: " (.getMessage e))))
      
      (catch Exception e (println (str "caught exception: " (.getMessage e))))
      (finally (println "This is our final block")))
   (println "Let's move on"))
(Example)

Вышеуказанная программа производит следующий вывод.

caught file exception: Example.txt (No such file or directory)
This is our final block
Let's move on

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

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

  • public String getMessage () — возвращает подробное сообщение об исключении, которое произошло. Это сообщение инициализируется в конструкторе Throwable.

  • public Throwable getCause () — Возвращает причину исключения, представленного объектом Throwable.

  • public String toString () — Возвращает имя класса, объединенного с результатом getMessage ().

  • public void printStackTrace () — печатает результат toString () вместе с трассировкой стека в System.err, поток вывода ошибок.

  • public StackTraceElement [] getStackTrace () — Возвращает массив, содержащий каждый элемент в трассировке стека. Элемент с индексом 0 представляет вершину стека вызовов, а последний элемент в массиве представляет метод в нижней части стека вызовов.

  • public Throwable fillInStackTrace () — Заполняет трассировку стека этого объекта Throwable текущей трассировкой стека, добавляя к любой предыдущей информации в трассировке стека.

public String getMessage () — возвращает подробное сообщение об исключении, которое произошло. Это сообщение инициализируется в конструкторе Throwable.

public Throwable getCause () — Возвращает причину исключения, представленного объектом Throwable.

public String toString () — Возвращает имя класса, объединенного с результатом getMessage ().

public void printStackTrace () — печатает результат toString () вместе с трассировкой стека в System.err, поток вывода ошибок.

public StackTraceElement [] getStackTrace () — Возвращает массив, содержащий каждый элемент в трассировке стека. Элемент с индексом 0 представляет вершину стека вызовов, а последний элемент в массиве представляет метод в нижней части стека вызовов.

public Throwable fillInStackTrace () — Заполняет трассировку стека этого объекта Throwable текущей трассировкой стека, добавляя к любой предыдущей информации в трассировке стека.

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

Live Demo

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (try
      (def string1 (slurp "Example.txt"))
      (println string1)
      
      (catch java.io.FileNotFoundException e (println (str "caught file
         exception: " (.toString e))))
      
      (catch Exception e (println (str "caught exception: " (.toString e))))
   (finally (println "This is our final block")))
   (println "Let's move on"))
(Example)

Вышеуказанная программа производит следующий вывод.