Java offre une approche robuste et orientée objet pour gérer les scénarios d’exception connue sous le nom de Gestion des exceptions en Java. Il y a quelque temps, j’ai écrit un long article sur la Gestion des exceptions en Java et aujourd’hui je liste quelques Questions importantes sur les exceptions Java avec réponses pour vous aider lors des entretiens.
- Qu’est-ce qu’une exception en Java ?
- Quels sont les mots-clés de gestion des exceptions en Java ?
- Expliquez la hiérarchie des exceptions Java ?
- Quels sont les méthodes importantes de la classe Exception en Java ?
- Expliquez la fonctionnalité ARM de Java 7 et le bloc multi-catch ?
- Quelle est la différence entre les exceptions vérifiées et non vérifiées en Java ?
- Quelle est la différence entre les mots-clés throw et throws en Java ?
- Comment écrire des exceptions personnalisées en Java ?
- Qu’est-ce que OutOfMemoryError en Java ?
- Quels sont les différents scénarios provoquant « Exception dans le thread principal » ?
- Quelle est la différence entre final, finally et finalize en Java ?
- Que se passe-t-il lorsqu’une exception est levée par la méthode main ?
- Pouvons-nous avoir un bloc catch vide?
- Fournissez quelques bonnes pratiques de gestion des exceptions en Java?
- Quel est le problème avec les programmes ci-dessous et comment le corrigeons-nous?
1. Qu’est-ce qu’une exception en Java?
Une exception est un événement d’erreur qui peut se produire pendant l’exécution d’un programme et perturber son déroulement normal. L’exception peut survenir dans différentes situations telles que des données incorrectes saisies par l’utilisateur, une défaillance matérielle, une défaillance de la connexion réseau, etc. Chaque fois qu’une erreur se produit lors de l’exécution d’une instruction Java, un objet exception est créé, puis JRE tente de trouver un gestionnaire d’exceptions pour traiter l’exception. Si un gestionnaire d’exceptions approprié est trouvé, alors l’objet exception est transmis au code du gestionnaire pour traiter l’exception, appelé attraper l’exception. Si aucun gestionnaire n’est trouvé, alors l’application lance l’exception vers l’environnement d’exécution et JRE termine le programme. Le framework de gestion des exceptions Java est utilisé pour gérer uniquement les erreurs d’exécution, les erreurs de compilation ne sont pas gérées par le framework de gestion des exceptions.
2. Quels sont les mots-clés de gestion des exceptions en Java?
Il existe quatre mots-clés utilisés dans la gestion des exceptions en Java.
- throw: Parfois, nous voulons explicitement créer un objet d’exception et ensuite le jeter pour arrêter le traitement normal du programme. Le mot-clé throw est utilisé pour lancer des exceptions vers le runtime afin de les gérer.
- throws: Lorsque nous lançons une exception vérifiée dans une méthode et que nous ne la gérons pas, alors nous devons utiliser le mot-clé throws dans la signature de la méthode pour indiquer au programme appelant les exceptions qui pourraient être lancées par la méthode. La méthode appelante peut gérer ces exceptions ou les propager à sa méthode appelante en utilisant le mot-clé
throws
. Nous pouvons fournir plusieurs exceptions dans la clause throws et elle peut également être utilisée avec la méthode main(). - try-catch: Nous utilisons un bloc try-catch pour la gestion des exceptions dans notre code. try marque le début du bloc et catch est à la fin du bloc try pour gérer les exceptions. Nous pouvons avoir plusieurs blocs catch avec un try et les blocs try-catch peuvent également être imbriqués. Le bloc catch nécessite un paramètre qui doit être de type Exception.
- enfin : Le bloc finally est facultatif et peut être utilisé uniquement avec un bloc try-catch. Puisque l’exception interrompt le processus d’exécution, nous pourrions avoir des ressources ouvertes qui ne seront pas fermées, donc nous pouvons utiliser le bloc finally. Le bloc finally s’exécute toujours, que qu’une exception se produise ou non.
3. Expliquez la hiérarchie des exceptions en Java?
Les exceptions Java sont hiérarchiques et l’héritage est utilisé pour catégoriser différents types d’exceptions. `Throwable` est la classe parent de la hiérarchie des exceptions Java et elle a deux objets enfants – `Error` et `Exception`. Les exceptions sont ensuite divisées en exceptions vérifiées et en exceptions d’exécution. Les `Errors` sont des scénarios exceptionnels qui sortent du cadre de l’application et il n’est pas possible de les anticiper et de s’en remettre, par exemple, une défaillance matérielle, un crash de la JVM ou une erreur de mémoire insuffisante. Les `Checked Exceptions` sont des scénarios exceptionnels que nous pouvons anticiper dans un programme et essayer de récupérer, par exemple, FileNotFoundException. Nous devrions attraper cette exception et fournir un message utile à l’utilisateur et le journaliser correctement à des fins de débogage. `Exception` est la classe parent de toutes les exceptions vérifiées. Les `Runtime Exceptions` sont causées par une mauvaise programmation, par exemple, en essayant de récupérer un élément du tableau. Nous devrions vérifier d’abord la longueur du tableau avant d’essayer de récupérer l’élément sinon cela pourrait générer une `ArrayIndexOutOfBoundsException` à l’exécution. `RuntimeException` est la classe parent de toutes les exceptions d’exécution.
4. Quels sont les méthodes importantes de la classe Java Exception?
Exception et toutes ses sous-classes ne fournissent aucune méthode spécifique et toutes les méthodes sont définies dans la classe de base Throwable.
- String getMessage() – Cette méthode renvoie la chaîne de message de Throwable et le message peut être fourni lors de la création de l’exception via son constructeur.
- String getLocalizedMessage() – Cette méthode est fournie afin que les sous-classes puissent la remplacer pour fournir les messages spécifiques à la locale au programme appelant. L’implémentation de cette méthode dans la classe Throwable utilise simplement la méthode
getMessage()
pour renvoyer le message d’exception. - synchronized Throwable getCause() – Cette méthode renvoie la cause de l’exception ou null si la cause est inconnue.
- String toString() – Cette méthode renvoie les informations sur Throwable sous forme de chaîne, la chaîne retournée contient le nom de la classe Throwable et le message localisé.
- void printStackTrace() – Cette méthode imprime les informations de la trace de la pile sur le flux d’erreur standard, cette méthode est surchargée et nous pouvons passer PrintStream ou PrintWriter en argument pour écrire les informations de la trace de la pile dans le fichier ou le flux.
Expliquez la fonctionnalité ARM de Java 7 et le bloc multi-catch ?
Si vous capturez de nombreuses exceptions dans un seul bloc try, vous remarquerez que le code du bloc catch semble très laid et se compose principalement de code redondant pour journaliser l’erreur, en gardant cela à l’esprit l’une des fonctionnalités de Java 7 était le bloc multi-catch où nous pouvons capturer plusieurs exceptions dans un seul bloc catch. Le bloc catch avec cette fonctionnalité ressemble à ceci :
catch(IOException | SQLException | Exception ex){
logger.error(ex);
throw new MyException(ex.getMessage());
}
La plupart du temps, nous utilisons le bloc finally juste pour fermer les ressources et parfois nous oublions de les fermer et obtenons des exceptions d’exécution lorsque les ressources sont épuisées. Ces exceptions sont difficiles à déboguer et nous pourrions avoir besoin de vérifier chaque endroit où nous utilisons ce type de ressource pour nous assurer que nous la fermons. Donc, l’une des améliorations de Java 7 était try-with-resources où nous pouvons créer une ressource dans l’instruction try elle-même et l’utiliser à l’intérieur du bloc try-catch. Lorsque l’exécution sort du bloc try-catch, l’environnement d’exécution ferme automatiquement ces ressources. Exemple de bloc try-catch avec cette amélioration :
try (MyResource mr = new MyResource()) {
System.out.println("MyResource created in try-with-resources");
} catch (Exception e) {
e.printStackTrace();
}
En savoir plus à ce sujet sur Java 7 ARM.
6. Quelle est la différence entre les exceptions vérifiées et non vérifiées en Java?
- Les exceptions vérifiées doivent être gérées dans le code à l’aide d’un bloc try-catch, sinon la méthode doit utiliser le mot-clé throws pour informer l’appelant des exceptions vérifiées qui pourraient être levées par la méthode. Les exceptions non vérifiées ne sont pas nécessaires à traiter dans le programme ou à mentionner dans la clause throws de la méthode.
Exception
est la superclasse de toutes les exceptions vérifiées tandis queRuntimeException
est la superclasse de toutes les exceptions non vérifiées. Notez que RuntimeException est la sous-classe de Exception.- Les exceptions vérifiées sont des scénarios d’erreur qui doivent être gérés dans le code, sinon vous obtiendrez une erreur de compilation. Par exemple, si vous utilisez FileReader pour lire un fichier, il lance
FileNotFoundException
et nous devons le capturer dans le bloc try-catch ou le renvoyer à nouveau à la méthode appelante. Les exceptions non vérifiées sont principalement causées par une programmation médiocre, par exemple, NullPointerException lors de l’invocation d’une méthode sur une référence d’objet sans s’assurer qu’elle n’est pas nulle. Par exemple, je peux écrire une méthode pour supprimer toutes les voyelles de la chaîne. Il incombe à l’appelant de s’assurer de ne pas passer une chaîne nulle. Je pourrais modifier la méthode pour gérer ces scénarios mais idéalement, l’appelant devrait s’en charger.
7. Quelle est la différence entre les mots clés throw et throws en Java ?
Le mot clé throws est utilisé avec la signature de la méthode pour déclarer les exceptions que la méthode pourrait renvoyer, tandis que le mot clé throw est utilisé pour interrompre le flux du programme et transmettre l’objet d’exception au moment d’exécution pour le gérer.
8. Comment écrire des exceptions personnalisées en Java ?
Nous pouvons étendre la classe Exception ou l’une de ses sous-classes pour créer notre propre classe d’exception personnalisée. La classe d’exception personnalisée peut avoir ses propres variables et méthodes que nous pouvons utiliser pour transmettre des codes d’erreur ou d’autres informations liées à l’exception au gestionnaire d’exception. Un exemple simple d’une exception personnalisée est illustré ci-dessous.
package com.journaldev.exceptions;
import java.io.IOException;
public class MyException extends IOException {
private static final long serialVersionUID = 4664456874499611218L;
private String errorCode="Unknown_Exception";
public MyException(String message, String errorCode){
super(message);
this.errorCode=errorCode;
}
public String getErrorCode(){
return this.errorCode;
}
}
9. Qu’est-ce que OutOfMemoryError en Java ?
OutOfMemoryError en Java est une sous-classe de java.lang.VirtualMachineError et elle est lancée par la JVM lorsqu’elle manque de mémoire heap. Nous pouvons résoudre cette erreur en fournissant plus de mémoire pour exécuter l’application Java via les options Java. $>java MonProgramme -Xms1024m -Xmx1024m -XX:PermSize=64M -XX:MaxPermSize=256m
10. Quels sont les différents scénarios causant une « Exception in thread main »?
Certains des scénarios d’exceptions de thread principal les plus courants sont :
- Exception in thread main java.lang.UnsupportedClassVersionError : Cette exception se produit lorsque votre classe Java est compilée à partir d’une autre version de JDK et que vous essayez de l’exécuter à partir d’une autre version de Java.
- Exception in thread main java.lang.NoClassDefFoundError : Il existe deux variantes de cette exception. La première est lorsque vous fournissez le nom complet de la classe avec l’extension .class. Le deuxième scénario est lorsque la classe n’est pas trouvée.
- Exception in thread main java.lang.NoSuchMethodError: main : Cette exception se produit lorsque vous essayez d’exécuter une classe qui n’a pas la méthode main.
- Exception dans le fil « main » java.lang.ArithmeticException: Chaque fois qu’une exception est levée à partir de la méthode principale, elle est imprimée dans la console. La première partie explique qu’une exception est levée à partir de la méthode principale, la deuxième partie imprime le nom de la classe de l’exception, puis après deux-points, elle imprime le message d’exception.
En savoir plus à ce sujet sur Java Exception dans le fil principal.
11. Quelle est la différence entre final, finally et finalize en Java?
final et finally sont des mots-clés en java tandis que finalize est une méthode. Le mot-clé final peut être utilisé avec des variables de classe afin qu’elles ne puissent pas être réassignées, avec la classe pour éviter l’extension par d’autres classes et avec des méthodes pour éviter leur remplacement par des sous-classes, le mot-clé finally est utilisé avec un bloc try-catch pour fournir des instructions qui seront toujours exécutées même si une exception survient, généralement finally est utilisé pour fermer les ressources. La méthode finalize() est exécutée par le ramasse-miettes (Garbage Collector) avant que l’objet ne soit détruit, c’est une excellente façon de s’assurer que toutes les ressources globales sont fermées. Parmi les trois, seul finally est lié à la gestion des exceptions en Java.
12. Que se passe-t-il lorsque une exception est lancée par la méthode principale ?
Lorsqu’une exception est lancée par une méthode main(), Java Runtime termine le programme et affiche le message d’exception ainsi que la trace de la pile dans la console système.
13. Peut-on avoir un bloc catch vide ?
Nous pouvons avoir un bloc catch vide, mais c’est un exemple de mauvaise programmation. Nous ne devrions jamais avoir un bloc catch vide car si l’exception est capturée par ce bloc, nous n’aurons aucune information sur l’exception et cela sera un cauchemar à déboguer. Il devrait y avoir au moins une instruction de journalisation pour enregistrer les détails de l’exception dans la console ou les fichiers journaux.
14. Fournir quelques bonnes pratiques de gestion des exceptions en Java ?
Quelques bonnes pratiques liées à la gestion des exceptions en Java sont :
- Utiliser des exceptions spécifiques pour faciliter le débogage.
- Lancez les exceptions tôt (échec rapide) dans le programme.
- Attrapez les exceptions tard dans le programme, laissez l’appelant gérer l’exception.
- Utilisez la fonctionnalité ARM de Java 7 pour vous assurer que les ressources sont fermées ou utilisez un bloc finally pour les fermer correctement.
- Journalisez toujours les messages d’exception à des fins de débogage.
- Utilisez un bloc multi-catch pour une fermeture plus propre.
- Utilisez des exceptions personnalisées pour lancer un seul type d’exception depuis votre API d’application.
- Suivez la convention de nommage, terminez toujours par Exception.
- Documentez les exceptions lancées par une méthode en utilisant @throws dans javadoc.
- Les exceptions sont coûteuses, alors lancez-les uniquement lorsque cela a du sens. Sinon, vous pouvez les attraper et fournir une réponse nulle ou vide.
En savoir plus à leur sujet en détail sur Meilleures pratiques de gestion des exceptions en Java.
15. Quel est le problème avec les programmes ci-dessous et comment les résoudre ?
Dans cette section, nous examinerons quelques questions de programmation liées aux exceptions Java.
-
Quel est le problème avec le programme ci-dessous?
package com.journaldev.exceptions; import java.io.FileNotFoundException; import java.io.IOException; public class TestException { public static void main(String[] args) { try { testExceptions(); } catch (FileNotFoundException | IOException e) { e.printStackTrace(); } } public static void testExceptions() throws IOException, FileNotFoundException{ } }
Le programme ci-dessus ne se compilera pas et vous obtiendrez un message d’erreur indiquant « L’exception FileNotFoundException est déjà capturée par IOException alternative ». Cela est dû au fait que FileNotFoundException est une sous-classe de IOException. Il existe deux façons de résoudre ce problème. La première consiste à utiliser un seul bloc catch pour les deux exceptions.
try { testExceptions(); }catch(FileNotFoundException e){ e.printStackTrace(); }catch (IOException e) { e.printStackTrace(); }
Une autre façon est de supprimer FileNotFoundException du bloc multi-catch.
try { testExceptions(); }catch (IOException e) { e.printStackTrace(); }
Vous pouvez choisir l’une de ces approches en fonction de votre code de bloc catch.
-
Quel est le problème avec le programme ci-dessous ?
package com.journaldev.exceptions; import java.io.FileNotFoundException; import java.io.IOException; import javax.xml.bind.JAXBException; public class TestException1 { public static void main(String[] args) { try { go(); } catch (IOException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); } } public static void go() throws IOException, JAXBException, FileNotFoundException{ } }
Le programme ne se compilera pas car FileNotFoundException est une sous-classe de IOException, donc le bloc catch de FileNotFoundException est inaccessible et vous obtiendrez un message d’erreur indiquant « Bloc catch inatteignable pour FileNotFoundException. Il est déjà géré par le bloc catch pour IOException ». Vous devez corriger l’ordre des blocs catch pour résoudre ce problème.
try { go(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); }
Remarquez que JAXBException n’est pas liée à IOException ou FileNotFoundException et peut être placée n’importe où dans la hiérarchie des blocs catch ci-dessus.
-
Quel est le problème avec le programme ci-dessous?
package com.journaldev.exceptions; import java.io.IOException; import javax.xml.bind.JAXBException; public class TestException2 { public static void main(String[] args) { try { foo(); } catch (IOException e) { e.printStackTrace(); }catch(JAXBException e){ e.printStackTrace(); }catch(NullPointerException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } } public static void foo() throws IOException{ } }
Le programme ne compilera pas car JAXBException est une exception vérifiée et la méthode foo() devrait lancer cette exception pour être capturée dans la méthode d’appel. Vous obtiendrez un message d’erreur comme « Bloc catch inaccessible pour JAXBException. Cette exception n’est jamais lancée à partir du corps de l’instruction try ». Pour résoudre ce problème, vous devrez supprimer le bloc catch de JAXBException. Remarquez que la capture de NullPointerException est valide car c’est une exception non vérifiée.
-
Quel est le problème avec le programme ci-dessous?
package com.journaldev.exceptions; public class TestException3 { public static void main(String[] args) { try{ bar(); }catch(NullPointerException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } foo(); } public static void bar(){ } public static void foo() throws NullPointerException{ } }
C’est une question piège, il n’y a aucun problème avec le code et il se compilera avec succès. Nous pouvons toujours capturer une Exception ou n’importe quelle exception non vérifiée même si elle n’est pas dans la clause throws de la méthode. De même, si une méthode (foo) déclare une exception non vérifiée dans la clause throws, il n’est pas obligatoire de la traiter dans le programme.
-
Quel est le problème avec le programme ci-dessous?
package com.journaldev.exceptions; import java.io.IOException; public class TestException4 { public void start() throws IOException{ } public void foo() throws NullPointerException{ } } class TestException5 extends TestException4{ public void start() throws Exception{ } public void foo() throws RuntimeException{ } }
Le programme ci-dessus ne se compilera pas car la signature de la méthode start() n’est pas la même dans la sous-classe. Pour résoudre ce problème, nous pouvons soit modifier la signature de la méthode dans la sous-classe pour qu’elle soit exactement la même que dans la superclasse, soit supprimer la clause throws de la méthode de la sous-classe comme indiqué ci-dessous.
@Override public void start(){ }
-
Quel est le problème avec le programme ci-dessous?
package com.journaldev.exceptions; import java.io.IOException; import javax.xml.bind.JAXBException; public class TestException6 { public static void main(String[] args) { try { foo(); } catch (IOException | JAXBException e) { e = new Exception(""); e.printStackTrace(); }catch(Exception e){ e = new Exception(""); e.printStackTrace(); } } public static void foo() throws IOException, JAXBException{ } }
Le programme ci-dessus ne se compilera pas car l’objet d’exception dans le bloc multi-catch est final et nous ne pouvons pas changer sa valeur. Vous obtiendrez une erreur de compilation indiquant « Le paramètre e d’un bloc multi-catch ne peut pas être assigné ». Nous devons supprimer l’assignation de « e » à un nouvel objet d’exception pour résoudre cette erreur. Lire plus à Java 7 bloc multi-catch.
C’est tout pour les questions d’interview sur les exceptions Java, j’espère que vous les aimerez. J’en ajouterai d’autres à la liste à l’avenir, assurez-vous de la mettre en signet pour une utilisation future.
Source:
https://www.digitalocean.com/community/tutorials/java-exception-interview-questions-and-answers