Clojure - Manejo de excepciones
Exception handlingSe requiere en cualquier lenguaje de programación para manejar los errores de tiempo de ejecución de modo que se pueda mantener el flujo normal de la aplicación. La excepción generalmente interrumpe el flujo normal de la aplicación, que es la razón por la que necesitamos usar el manejo de excepciones en nuestra aplicación.
La excepción se clasifica ampliamente en las siguientes categorías:
Checked Exception- Las clases que amplían la clase Throwable, excepto RuntimeException y Error, se conocen como excepciones comprobadas. Por ejemplo, IOException, SQLException, etc. Las excepciones marcadas se comprueban en tiempo de compilación.
Consideremos el siguiente programa que realiza una operación en un archivo llamado Example.txt. Sin embargo, siempre puede haber un caso en el que el archivo Example.txt no exista.
(ns clojure.examples.example
(:gen-class))
;; This program displays Hello World
(defn Example []
(def string1 (slurp "Example.txt"))
(println string1))
(Example)
Si el archivo Example.txt no existe, el programa generará la siguiente excepción.
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)
De la excepción anterior, podemos ver claramente que el programa generó una FileNotFoundException.
Unchecked Exception- Las clases que amplían RuntimeException se conocen como excepciones no comprobadas. Por ejemplo, ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException, etc. Las excepciones no comprobadas no se comprueban en tiempo de compilación, sino que se comprueban en tiempo de ejecución.
Un caso clásico es la excepción ArrayIndexOutOfBoundsException, que ocurre cuando intenta acceder a un índice de una matriz que es mayor que la longitud de la matriz. A continuación se muestra un ejemplo típico de este tipo de error.
(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)
Cuando se ejecuta el código anterior, se generará la siguiente excepción.
caught exception: java.lang.ArrayIndexOutOfBoundsException: 5
This is our final block
Let's move on
Error
El error es irrecuperable, por ejemplo, OutOfMemoryError, VirtualMachineError, AssertionError, etc. Estos son errores de los que el programa nunca puede recuperarse y provocarán que el programa se bloquee. Ahora necesitamos algún mecanismo para detectar estas excepciones para que el programa pueda continuar ejecutándose si existen estas excepciones.
El siguiente diagrama muestra cómo se organiza la jerarquía de excepciones en Clojure. Todo se basa en la jerarquía definida en Java.
Captura de excepciones
Al igual que otros lenguajes de programación, Clojure proporciona el bloque normal 'try-catch' para detectar excepciones a medida que ocurren.
A continuación se muestra la sintaxis general del bloque try-catch.
(try
(//Protected code)
catch Exception e1)
(//Catch block)
Todo su código que podría generar una excepción se coloca en el Protected code block.
En el catch block, puede escribir código personalizado para manejar su excepción para que la aplicación pueda recuperarse de la excepción.
Veamos nuestro ejemplo anterior que generó una excepción de archivo no encontrado y veamos cómo podemos usar el bloque try catch para detectar la excepción generada por el programa.
(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)
El programa anterior produce la siguiente salida.
caught exception: Example.txt (No such file or directory)
Del código anterior, terminamos el código defectuoso en el try block. En el bloque de captura, solo estamos detectando nuestra excepción y enviando un mensaje de que se ha producido una excepción. Entonces, ahora tenemos una forma significativa de capturar la excepción, que es generada por el programa.
Múltiples bloques de captura
Uno puede tener múltiples bloques de captura para manejar múltiples tipos de excepciones. Para cada bloque de captura, dependiendo del tipo de excepción generada, escribiría código para manejarlo en consecuencia.
Modifiquemos nuestro código anterior para incluir dos bloques de captura, uno que es específico para nuestra excepción de archivo no encontrado y el otro es para un bloque de excepción general.
(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)
El programa anterior produce la siguiente salida.
caught file exception: Example.txt (No such file or directory)
Let's move on
De la salida anterior, podemos ver claramente que nuestra excepción fue detectada por el bloque de captura 'FileNotFoundException' y no por el general.
Finalmente bloquear
El bloque finalmente sigue a un bloque try o un bloque catch. Un último bloque de código siempre se ejecuta, independientemente de la ocurrencia de una excepción.
El uso de un bloque finalmente le permite ejecutar cualquier declaración de tipo limpieza que desee ejecutar, sin importar lo que suceda en el código protegido. A continuación se muestra la sintaxis de este bloque.
(try
(//Protected code)
catch Exception e1)
(//Catch block)
(finally
//Cleanup code)
Modifiquemos el código anterior y agreguemos el bloque de código finalmente. A continuación se muestra el fragmento de código.
(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)
El programa anterior produce la siguiente salida.
caught file exception: Example.txt (No such file or directory)
This is our final block
Let's move on
En el programa anterior, puede ver que el bloque final también se implementa después de que el bloque catch detecta la excepción requerida.
Dado que Clojure deriva su manejo de excepciones de Java, similar a Java, los siguientes métodos están disponibles en Clojure para administrar las excepciones.
public String getMessage()- Devuelve un mensaje detallado sobre la excepción que se ha producido. Este mensaje se inicializa en el constructor Throwable.
public Throwable getCause() - Devuelve la causa de la excepción representada por un objeto Throwable.
public String toString() - Devuelve el nombre de la clase concatenada con el resultado de getMessage ().
public void printStackTrace() - Imprime el resultado de toString () junto con el seguimiento de la pila en System.err, el flujo de salida del error.
public StackTraceElement [] getStackTrace()- Devuelve una matriz que contiene cada elemento en el seguimiento de la pila. El elemento en el índice 0 representa la parte superior de la pila de llamadas y el último elemento de la matriz representa el método en la parte inferior de la pila de llamadas.
public Throwable fillInStackTrace() - Rellena el seguimiento de la pila de este objeto Throwable con el seguimiento de la pila actual, añadiendo a cualquier información anterior en el seguimiento de la pila.
A continuación se muestra el código de ejemplo que utiliza algunos de los métodos enumerados anteriormente.
(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)
El programa anterior produce la siguiente salida.
caught file exception: java.io.FileNotFoundException: Example.txt (No such file
or directory)
This is our final block
Let's move on