Clojure - Traitement des exceptions

Exception handlingest requis dans tout langage de programmation pour gérer les erreurs d'exécution afin que le flux normal de l'application puisse être maintenu. Les exceptions perturbent généralement le flux normal de l'application, raison pour laquelle nous devons utiliser la gestion des exceptions dans notre application.

L'exception est généralement classée dans les catégories suivantes -

  • Checked Exception- Les classes qui étendent la classe Throwable à l'exception de RuntimeException et Error sont appelées exceptions vérifiées. Par exemple, IOException, SQLException, etc. Les exceptions vérifiées sont vérifiées au moment de la compilation.

Considérons le programme suivant qui effectue une opération sur un fichier appelé Example.txt. Cependant, il peut toujours y avoir un cas où le fichier Example.txt n'existe pas.

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

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

Si le fichier Example.txt n'existe pas, l'exception suivante sera générée par le programme.

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)

À partir de l'exception ci-dessus, nous pouvons clairement voir que le programme a déclenché une FileNotFoundException.

  • Unchecked Exception- Les classes qui étendent RuntimeException sont appelées exceptions non vérifiées. Par exemple, ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException, etc. Les exceptions non vérifiées ne sont pas vérifiées au moment de la compilation, mais sont vérifiées au moment de l'exécution.

Un cas classique est l'exception ArrayIndexOutOfBoundsException qui se produit lorsque vous essayez d'accéder à un index d'un tableau qui est supérieur à la longueur du tableau. Voici un exemple typique de ce type d'erreur.

(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)

Lorsque le code ci-dessus est exécuté, l'exception suivante sera déclenchée.

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

Erreur

L'erreur est irrécupérable, par exemple OutOfMemoryError, VirtualMachineError, AssertionError, etc. Ce sont des erreurs dont le programme ne peut jamais récupérer et qui provoqueront le crash du programme. Nous avons maintenant besoin d'un mécanisme pour intercepter ces exceptions afin que le programme puisse continuer à s'exécuter si ces exceptions existent.

Le diagramme suivant montre comment la hiérarchie des exceptions dans Clojure est organisée. Tout est basé sur la hiérarchie définie en Java.

Attraper les exceptions

Tout comme les autres langages de programmation, Clojure fournit le bloc normal «try-catch» pour intercepter les exceptions au fur et à mesure qu'elles se produisent.

Voici la syntaxe générale du bloc try-catch.

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

Tout votre code qui pourrait soulever une exception est placé dans le Protected code block.

dans le catch block, vous pouvez écrire du code personnalisé pour gérer votre exception afin que l'application puisse récupérer de l'exception.

Regardons notre exemple précédent qui a généré une exception de fichier introuvable et voyons comment nous pouvons utiliser le bloc try catch pour intercepter l'exception levée par le programme.

(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)

Le programme ci-dessus produit la sortie suivante.

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

À partir du code ci-dessus, nous enveloppons le code défectueux dans le try block. Dans le bloc catch, nous interceptons simplement notre exception et émettons un message indiquant qu'une exception s'est produite. Ainsi, nous avons maintenant un moyen significatif de capturer l'exception, qui est générée par le programme.

Blocs de capture multiples

On peut avoir plusieurs blocs catch pour gérer plusieurs types d'exceptions. Pour chaque bloc catch, selon le type d'exception déclenchée, vous écririez du code pour le gérer en conséquence.

Modifions notre code précédent pour inclure deux blocs catch, l'un qui est spécifique à notre exception de fichier non trouvé et l'autre est pour un bloc d'exception générale.

(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)

Le programme ci-dessus produit la sortie suivante.

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

À partir de la sortie ci-dessus, nous pouvons clairement voir que notre exception a été interceptée par le bloc catch 'FileNotFoundException' et non par le bloc général.

Enfin bloquer

Le bloc finally suit un bloc try ou un bloc catch. Un bloc de code finally s'exécute toujours, indépendamment de l'occurrence d'une exception.

L'utilisation d'un bloc finally vous permet d'exécuter toutes les instructions de type nettoyage que vous souhaitez exécuter, peu importe ce qui se passe dans le code protégé. Voici la syntaxe de ce bloc.

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

Modifions le code ci-dessus et ajoutons le dernier bloc de code. Voici l'extrait de code.

(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)

Le programme ci-dessus produit la sortie suivante.

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

À partir du programme ci-dessus, vous pouvez voir que le bloc final est également implémenté une fois que le bloc catch a détecté l'exception requise.

Puisque Clojure dérive sa gestion des exceptions de Java, similaire à Java, les méthodes suivantes sont disponibles dans Clojure pour gérer les exceptions.

  • public String getMessage()- Renvoie un message détaillé sur l'exception qui s'est produite. Ce message est initialisé dans le constructeur Throwable.

  • public Throwable getCause() - Renvoie la cause de l'exception représentée par un objet Throwable.

  • public String toString() - Renvoie le nom de la classe concaténée avec le résultat de getMessage ().

  • public void printStackTrace() - Imprime le résultat de toString () avec la trace de la pile dans System.err, le flux de sortie d'erreur.

  • public StackTraceElement [] getStackTrace()- Renvoie un tableau contenant chaque élément de la trace de pile. L'élément à l'index 0 représente le haut de la pile d'appels et le dernier élément du tableau représente la méthode au bas de la pile d'appels.

  • public Throwable fillInStackTrace() - Remplit la trace de pile de cet objet Throwable avec la trace de pile actuelle, en ajoutant à toutes les informations précédentes dans la trace de pile.

Voici l'exemple de code qui utilise certaines des méthodes répertoriées ci-dessus.

(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)

Le programme ci-dessus produit la sortie suivante.

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