2009-02-10 4 views
4

Il y a certaines exceptions prédéfinies dans Java, qui, si elles sont lancées, signalent que quelque chose de sérieux est arrivé et que vous feriez mieux d'améliorer votre code plutôt que de les attraper dans un bloc catch (si je l'ai bien compris) . Mais je trouve de nombreux programmes dont je donne les résultats suivants:Catching exceptions in Java

} catch (IOException e) { 
    ... 
} catch (FileNotFoundException e) { 
    .... 
} 

et je pensais que IOException et FileNotFoundException sont exactement ce genre d'exceptions, que nous ne devrions pas attraper dans un bloc catch. Pourquoi les gens font ça? Est-il préférable de les attraper comme ça? Le compilateur Java avertit quand même de tout problème de ce genre.

Merci.

Répondre

14

Non, il n'y a rien de mal à attraper IOException et FileNotFoundException - si vous pouvez vraiment poignée ces exceptions. C'est l'élément important - pouvez-vous vraiment aller de l'avant face à cette exception? Parfois vous le pouvez - très souvent au plus haut niveau d'un serveur, par exemple, où juste parce qu'une demande échoue ne signifie pas que le suivant ne peut pas continuer. Moins souvent dans les applications client, bien que cela dépende beaucoup de la situation. Vous ne pouvez pas lire un fichier lorsque vous essayez d'effectuer une importation par lot? Ok, interrompre l'opération, mais ne fermez pas nécessairement le processus entier ...

Vous ne devriez pas les avoir de cette façon ronde, il est vrai - le FileNotFoundException serait masqué par le IOException dont il dérive. Heureusement, le compilateur à plat vous empêche de le faire.

3

Le faire ceci afin de gérer différents types d'exceptions différemment. Généralement, vous allez vouloir capturer les exceptions les plus granulaires en premier, si vous mettez les exceptions plus larges au début de votre bloc catch, vous allez d'abord exécuter ce code, puis frapper le bloc finally. Jon a raison, le catch qui attrape l'IOException va attraper toutes les IOExceptions et tout sous-type d'IOException, et puisque FileNotFoundException est un type d'IOException, il ne touchera jamais le 2nd catch.

5

L'ordre que vous affichez, avec IOException pris avant FileNotFoundException est erroné. Puisque FileNotFoundException s'étend IOException, quand un FileNotFoundException est levé, le premier gestionnaire sera utilisé, et le deuxième gestionnaire est un code mort.

Je ne l'ai pas essayé, mais je suis un peu surpris si cela compile. Un outil d'analyse statique comme FindBugs permettrait d'attraper cette erreur, j'espère.

Dans la mesure où vous devrait prendre un FileNotFoundException, cela dépend de l'appelant. Cependant, je dirai qu'un FileNotFoundException peut souvent être récupéré de façon significative — en invitant un autre fichier, en essayant un emplacement de repli — au lieu de simplement enregistrer l'erreur ou abandonner le processus.

+0

Très bon point, et belle réponse. – hotshot309

4

Il existe deux types d'exceptions dans Java, les exceptions vérifiées et les exceptions non contrôlées.

Les exceptions vérifiées doivent être gérées dans un bloc catch. Ne pas le faire provoquera une erreur de compilation. IOException est un exemple d'exception vérifiée et doit être géré. Ce que vous faites ici dépend de l'application en question, mais l'exception doit être gérée pour que le compilateur reste content.

Les exceptions non contrôlées n'ont pas besoin d'être interceptées. Toutes les classes qui s'étendent à partir de RuntimeException ne sont pas cochées.Un bon exemple de ceci est une exception NullPointerException ou une exception ArrayIndexOutOfBoundsException. Le compilateur ne vous force pas à intercepter ces exceptions, mais elles peuvent toujours se produire lorsque votre programme s'exécute, ce qui provoque son blocage. Pour l'enregistrement, IOException peut être lancé pour quelque chose d'aussi simple que d'essayer d'ouvrir un fichier qui n'existe pas. C'est une bonne idée de gérer quelque chose comme ça et récupérer gracieusement (dialogue à l'utilisateur disant que le fichier n'existe pas et faire réapparaître une boîte de dialogue ouverte), plutôt que de laisser le programme tomber en panne.

3

En tant que Jon says, attraper ces exceptions est bien dans de nombreux cas. Le genre d'exceptions que vous ne devriez pas attraper sont des choses comme NullPointerException et ArrayIndexOutOfBoundsException, elles indiquent des bogues dans votre code.

Java a deux types d'exception: les exceptions vérifiées et les exceptions non contrôlées (celles qui héritent de RuntimeException).

Les exceptions cochées, telles que IOException, sont généralement utilisées pour les scénarios imprévisibles qui ne peuvent pas être évités en écrivant un meilleur code. Le fait qu'ils soient vérifiés signifie que le compilateur vous force à écrire du code qui tient compte de la possibilité du scénario exceptionnel. Par exemple, vous devez considérer la possibilité d'une exception FileNotFoundException car vous ne pouvez pas garantir que le fichier existera (quelqu'un pourrait le déplacer pendant que votre programme est en cours d'exécution). Une exception IOException peut se produire car une connexion réseau est supprimée. Le compilateur vous oblige à fournir une stratégie pour traiter ces cas, même si c'est juste pour passer le test en permettant à l'exception de se propager dans la pile pour que le code appelant puisse être traité. D'autre part, les exceptions non contrôlées sont mieux utilisées pour les choses qui peuvent être évitées en changeant le code. Une exception NullPointerException peut toujours être évitée si le code vérifie la possibilité d'une référence nulle. De même, si vous faites attention avec vos index, vous n'obtiendrez jamais une exception ArrayIndexOutOfBoundsException. Le compilateur ne vous oblige pas à gérer ces scénarios car ils représentent des bogues qui devraient être corrigés.

3

Je pensais que IOException et FileNotFoundException sont exactement ce genre d'exceptions

Nope, ce sont en fait les « autres » types d'exceptions, le genre qui vont au-delà de vos compétences en programmation. Quel que soit le niveau de programmation, le compilateur et les bibliothèques vous rendent "conscient" que quelque chose peut arriver.

Pensez à ce scénario:

Vous créez une application qui enregistre les données dans un dossier temporaire.

Tout va bien, vous avez vérifié que le dossier existe, et sinon, vous le créez vous-même.

Ensuite, vous écrivez 2 Mo dans ce dossier temporaire. Soudain, d'autres processus du système, supprime votre dossier temporaire, et vous ne pouvez plus écrire.

Il n'y a rien que vous pouvez faire pour empêcher cela par programme, dans certains systèmes, cette opération pourrait se produire (Dans unix, l'utilisateur root peut effectuer rm -rf/tmp et vous ne pouvez rien y faire. En vous obligeant à vérifier ce type d'exceptions dans le code, les concepteurs de la plate-forme pensaient qu'au moins vous en étiez conscient.

Jon is correct parfois il n'y a rien que vous pouvez faire à ce sujet, l'exploitation forestière probablement avant que le programme meurt, qui est considéré comme « gérer l'exception » (mauvaise poignée oui, mais gérer au moins)

try { 
    .... 
} catch(IOException ioe) { 
    logger.severe( 
     String.format("Got ioe while writting file %s. Data was acquired using id = %d, the message is: %s", 
      fileName, 
      idWhereDataCame, 
      ioe.getMessage())); 
    throw ioe; 
} 

Une autre chose vous pouvez faire est de "chaîner" l'exception pour s'adapter à l'abstraction.

Probablement votre application, est dotée d'une interface graphique, montrant une exception d'E/S à l'utilisateur ne signifie rien ou pourrait être un security vulnerability. Un message modifié pourrait être envoyé.

try { 
    .... 
} catch(IOException ioe) { 
    throw new EndUserException("The operation you've requeste could not be completed, please contact your administrator" , ioe); 
}  

Et le EndUserException pourrait être emprisonné quelque part dans l'IUG et présenté à l'utilisateur dans un message de dialogue (au lieu de simplement disparaître l'application dans ses yeux sans plus d'informations). Bien sûr, il n'y avait rien que vous puissiez faire pour récupérer cette IOException, mais au moins vous mourrez avec style: P

Enfin un code client, pourrait utiliser différentes implémentations, et toutes les exceptions n'auraient pas de sens. Par exemple, détrompez-vous sur le premier scénario. Cette même "opération" pourrait avoir trois types de services "plugins" pour effectuer l'enregistrement des données.

a) Write the data to a file. 
b) Or, write to a db 
c) Or write to a remote server. 

L'interface ne doit pas jeter:

java.io.IOException 
java.sql.SQLException 

ni

java.net.UnknownHostException 

Mais au lieu quelque chose comme

my.application.DataNotSavedException 

et les différentes implémentations gérerait l'exception à la bonne niveau, et transformer à l'abstraction appropriée:

Code client:

DataSaver saver = DataServer.getSaverFor("someKeyIdString"); 

try { 
    saver.save(myData); 
} catch(DataNotSavedException dnse) { 

    // Oh well... . 
    ShowEndUserError("Data could not be saved due to : " dnse.getMessage()); 
} 

Code de mise en œuvre:

class ServerSaver implements DataSaver { 
.... 
    public void save(Data data) throws DataNotSavedException { 
     // Connect the remore server. 
     try { 
      Socket socket = new Socket(this.remoteServer, this.remotePort); 
      OuputStream out = socket.getOut.... 

      .... 
      .... 
     } catch (UnknownHostException uhe) { 
      // Oops.... 
      throw new DataNotSavedException(uhe); 
     } 
    } 
} 

FileSaver et DatabaseSaver ferait quelque chose de similaire.

Tous ces éléments sont Exceptions vérifiées car le compilateur vous invite à les vérifier.

Quand utiliser l'un ou l'autre (cochée/décochée): here

Il existe deux autres types: here

Et enfin une explication beaucoup plus simple du Runtime est: here

0

Pour prendre cette idée de côté un peu: peut-être dans un autre domaine c'est plus clair

Que faites-vous si la voiture en fr Vous arrêtez soudainement.

Stop!

Nous gérons donc l'exception.

Donc, retour à code:

Que faites-vous si le fichier dont vous avez besoin est pas disponible?

soit

  1. une sauvegarde. Compilé en tant que ressource car il fait partie de votre programme . Je ne plaisante pas.
  2. IFF C'est un fichier fourni par l'utilisateur: Dites à l'utilisateur; c'est leur dossier.
  3. Abandonnez le programme avec un message à l'utilisateur car votre logiciel SYSTEM est cassé.

Je suis d'avis qu'il n'y a pas de quatrième option.

Nos frères C#/VC++ choisissent des exceptions non vérifiées. De nombreux "experts" pensent que les exceptions vérifiées sont mauvaises: mon argument est que la vie est difficile, surmontez-la. Les exceptions cochées représentent les modes de défaillance connus: et doivent être adressées. Votre diagramme en arête de poisson a une allonge droite pour un fonctionnement normal et se détache du côté pour des pannes. Les exceptions vérifiées sont les échecs anticipés.

Maintenant, une fois que vous commencez à gérer les exceptions d'exécution, cela devient intéressant. Un programme Java peut fonctionner normalement normalement avec des fonctions qui ne fonctionnent pas. Par là, je veux dire qu'ils lancent des exceptions de pointeurs NULL, des erreurs de bornes de tableau, des arguments invalides et un espace de tas vide. Cela rend la livraison incrémentielle tout à fait réalisable.

(Si jamais vous attrapez des erreurs d'exécution, les log. Sinon, vous savez jamais arranger les choses)