2010-12-09 40 views
1

J'ai besoin d'un code pour être déclenché si une erreur se produit. Fondamentalement, j'ai besoin d'un bloc finally qui s'exécute uniquement en cas d'exception. Je mettre en œuvre ainsi:Comment implémenter `finally` pour un cas d'erreur en Java

HttpURLConnection post(URL url, byte[] body) throws IOException { 
    HttpURLConnection connection = url.openConnection(); 
    try { 
     OutputStream out = connection.getOutputStream(); 
     try { 
      out.write(body); 
     } finally { 
      out.close(); 
     } 
     return connection; 
    } catch (Throwable t) { 
     connection.disconnect(); 
     throw t; 
    } 
} 

Attend fin, sauf qu'il ne compilera pas: ma fonction ne peut pas jeter Throwable.

Je pourrais réécrire:

} catch (RuntimeException e) { 
     connection.disconnect(); 
     throw e; 
    } catch (IOException e) { 
     connection.disconnect(); 
     throw e; 
    } 

Mais je suis) manque toutes les erreurs et b) doivent fixer ce code chaque fois que je change ma mise en œuvre de lancer différents types d'exceptions.

Est-il possible de gérer cela génériquement?

+4

Les exceptions ne sont-elles pas vérifiées juste * fantastique? * – cdhowie

+0

@cdhowie: Je n'aime pas non plus les exceptions vérifiées, mais c'est vraiment un cas de Error et Throwable en cours de vérification mais pas vérifié; rien dans le runtime ne déclare "thrx XxxError", mais si vous essayez de (re) lancer XxxError soudainement il est coché - HUH ?? Qu'est-ce qui se passe avec ça? Les exceptions vérifiées devraient avoir été faites avec une sous-classe CheckedException de Throwable qui est vérifiée par le compilateur, pas la "magie" actuelle - bien sûr qui me permet de renvoyer une exception vérifiée comme Throwable, mais je ne suis pas sûr que ce soit un tel mauvaise chose. –

+0

@Software Monkey: en fait 'Error' n'est pas coché - je viens de le vérifier. :) Vous pouvez certainement attraper et relancer 'Error' sans le mentionner dans la clause' throws'.Cela ajouterait un autre cas à ma solution, le rendant encore moins facile à maintenir. La réalité est que, au lieu de CheckedException, Java va avec deux arbres non contrôlés, RuntimeException et Error, avec tout le reste à vérifier. – SnakE

Répondre

11

Vous pouvez utiliser un bloc finally et ajouter un indicateur pour indiquer le succès.

bool success = false; 
try { 
    //your code 
    success = true; 
    return retVal; 
} finally { 
    if (!success) { 
     //clean up 
    } 
} 
+0

C'est certainement beaucoup mieux que ma liste des types d'exception. Je vais m'en tenir à cette solution pour le moment - dommage que ce ne soit pas une construction de langage. – SnakE

3

Throwable a deux sous-classes, Error et Exception. Javadocs pour Error disent:

Une erreur est une sous-classe de Throwable qui indique des problèmes graves qu'une application raisonnable ne devrait pas essayer d'attraper . La plupart de ces erreurs sont conditions anormales. L'erreur ThreadDeath , bien qu'une condition "normale", est également une sous-classe d'erreur, car la plupart des applications ne devraient pas essayer d'attraper il.

Donc, à moins que cela est une situtation vraiment inhabituelle, vous pouvez simplement se concentrer sur Exception:

catch (IOException e) { 
    connection.disconnect(); 
    throw e; 
} 
catch (RuntimeException e) { 
    connection.disconnect(); 
    throw e; 
} 
catch (Exception e) { 
    connection.disconnect(); 
    throw new IOException(e); 
} 
+0

Mise à jour pour prendre en compte uniquement le lancement de IOException –

+0

L'emballage de tout dans IOException ne me semble pas être une bonne idée. Tout ArrayOutOfBounds finira comme IO de cette façon. Vous avez raison: les erreurs sont plus exceptionnelles que les exceptions, mais le bloc 'finally' fonctionne pour tout ce qui est transparent sans changer le type d'exception. J'aimerais reproduire ce comportement le plus près possible. – SnakE

+0

@SnakE - La technique 'finally' ne doit pas être bouclée car elle n'autorise * aucun * autre type d'exception en dehors de IOException (et RuntimeException, mais RuntimeException peut également être retiré dans son propre bloc). Si vous n'avez pas besoin de prendre en charge d'autres types d'exceptions, vous pouvez supprimer le bloc générique 'Exception' de mon exemple. –

-1

À moins que je me trompe une exception aurait pas besoin d'un bloc finally pour arrêter l'exécution et faire quelque chose dont vous avez besoin, comme le nettoyage ou l'atténuation des erreurs. Les erreurs devraient provenir de vos classes implémentées et des méthodes qui sont fondamentalement vos idées. Pensez au flux d'exécution et à la propagation des erreurs. Si votre méthode ci-dessus n'attrape pas une exception particulière, tout ce qui l'a appelée verra l'exception.

Throwable est juste une classe de haut niveau avec des sous-classes. L'exception étant généralement une prise tout. Et rappelez-vous que vous pouvez également implémenter vos propres exceptions pour gérer la tâche.