Question

Java vous permet de créer un tout nouveau sous-type de Throwable, par exemple:

public class FlyingPig extends Throwable { ... }

très rarement , je peux faire quelque chose comme ceci:

throw new FlyingPig("Oink!");

et bien sûr ailleurs:

try { ... } catch (FlyingPig porky) { ... }

Mes questions sont les suivantes:

  • Est-ce une mauvaise idée? Et si oui, pourquoi?
    • ce qui aurait pu être fait pour prévenir cette sous-typage si elle est une mauvaise idée?
    • Comme il est impossible de prévenir (pour autant que je sache), ce qui pourrait entraîner des catastrophes?
  • Si ce n'est pas une si mauvaise idée, pourquoi pas?
    • Comment pouvez-vous faire quelque chose utile du fait que vous pouvez extends Throwable?

Scénario proposé # 1

Un scénario où j'étais vraiment tenté de faire quelque chose comme ceci a les propriétés suivantes:

  • Le "événement" est quelque chose que par arriver. Il est devrait . Il est très certainement pas un Error, et il n'y a rien Exception-al quand il se produit.
    • Parce qu'il est devrait , il y aura une catch attendait. Il ne sera pas « lapsus » quoi que ce soit passé. Il ne sera pas « échapper » de toute tentative de catch Exception générale et / ou Error.
  • Le "événement" arrive très rarement .
  • Quand il arrive, en général il y a une trace de pile profonde.

Alors peut-être il est clair maintenant ce que je veux dire. FlyingPig est Résultat d'une recherche récursive exhaustive

L'objet à rechercher existe: il est seulement une question de trouver dans la grande mer qui est l'espace de recherche. Le processus de recherche sera longue, de sorte que le coût relativement coûteux de la gestion des exceptions est négligeable. En fait, l'alternative de construction de flux de contrôle traditionnel de l'aide d'un drapeau boolean isFound peut être plus cher, car il doit être vérifié de façon continue tout au long du processus de recherche, très probablement à tous les niveaux de la récursion. Cette vérification échouera 99,99% du temps, mais il est absolument nécessaire de propager la condition de terminaison. D'une certaine manière, alors que efficace , le chèque est inefficace

Par simple throw-ing un FlyingPig lorsque se trouve l'objet recherché, vous n'avez pas encombrer le code avec la gestion du drapeau boolean isFound. Non seulement le code plus propre à cet égard, mais il peut courir plus vite en raison de cette omission.

Donc, pour résumer, le choix se situe entre ces deux:

  • Approche traditionnelle flux de contrôle
    • Utilisez un boolean isFound, vérifié en permanence
    • 99,99% du temps, le chèque est un « déchet », parce qu'il serait encore false
    • Quand il devient finalement true, vous arrêtez récursion et vous devez vous assurer que vous pouvez bien dérouleur à l'appel initial.
  • approche FlyingPig
    • Ne pas pris la peine avec un boolean isFound.
    • Si trouvé, juste throw new FlyingPig(); il de devrait , donc il y aura un catch pour elle.
    • Pas de gestion du drapeau boolean, aucune vérification gaspillée si vous avez besoin de continuer, pas tenue de livres à la main Déroulez le récursivité, etc.

Questions:

  • Est-ce technique de (ab) en utilisant exception valable? (Est-ce un nom là, il?)
  • Si elle est valide, devrait FlyingPig extends Throwable, ou est Exception très bien? (Même si il n'y a rien d'exceptionnel ses circonstances?)
Était-ce utile?

La solution

Je dirais qu'il est une très mauvaise idée. Beaucoup de code est mis en œuvre sur l'hypothèse que si vous attrapez Error et Exception vous avez pris toutes les exceptions possibles. Et la plupart des tutoriels et manuels vous diront la même chose. En créant une sous-classe directe de Throwable vous créez potentiellement toutes sortes de problèmes de maintenance et d'interopérabilité.

Je ne peux penser à aucune raison de prolonger Throwable. Étendre Exception ou RuntimeException à la place.

EDIT -. En réponse au scénario proposé par l'OP # 1

Les exceptions sont un moyen très coûteux de traiter avec le contrôle de flux « normal ». Dans certains cas, nous parlons milliers d'instructions supplémentaires exécutées pour créer, lancer et attraper une exception. Si vous allez ignorer les exceptions acceptées de sagesse et d'utilisation pour le contrôle de flux non exceptionnel, utiliser un sous-type de Exception. Essayer de faire semblant quelque chose est un « événement » pas une « exception » en déclarant est un sous-type de Throwable ne va pas réaliser quoi que ce soit.

Cependant, il est erroné de confondre une exception avec une erreur, erreur, mal, peu importe. Et il y a mauvais rien avec un représentant « événement exceptionnel qui n'est pas une erreur, erreur, mal, ou tout autre » en utilisant une sous-classe de Exception. La clé est que l'événement doit être exceptionnelle ; dire hors de l'ordinaire, qui se passe très rarement, ...

En résumé, un FlyingPig ne peut pas être une erreur, mais cela ne justifie pas de ne pas déclarer comme un sous-type de Exception.

Autres conseils

  

Cette technique est-de (ab) en utilisant exception valable? (Est-ce un nom là, il?)

À mon avis, ce n'est pas une bonne idée:

  • Il viole le principe de moindre étonnement , il rend le code plus difficile à lire, en particulier s'il n'y a rien exception al à ce sujet.
  • exception Lancer est une opération très coûteuse en Java (peut-être pas un problème cependant).

Exception devrait juste pas être utilisé pour de contrôle de flux. Si je devais nommer cette technique, je l'appellerais une odeur de code ou d'un modèle de lutte contre.

Voir aussi:

  

Si elle est valide, devrait FlyingPig étend Throwable, ou est Exception très bien? (Même si il n'y a rien d'exceptionnel ses circonstances?)

Il pourrait y avoir des situations où vous voulez prises Throwable non seulement attraper Exception mais aussi Error mais il est rare, les gens ne sont généralement pas prises Throwable. Mais je ne à trouver une situation où vous souhaitez lancer une sous-classe de Throwable.

Et je pense aussi que l'extension Throwable ne fait pas les choses semblent moins « exception-al » , ils font paraître pire - qui contrecarre totalement l'intention.

Pour conclure, si vous voulez vraiment jeter quelque chose, lancer une sous-classe de Exception.

Voir aussi:

Voici un blog de John Rose, architecte HotSpot:

http://blogs.oracle.com/jrose/entry/longjumps_considered_inexpensive

Il est sur le point « abusant » exceptions pour le contrôle des flux. Un peu différent cas d'utilisation, mais .. En bref, cela fonctionne très bien - si vous Préallouer / clone vos exceptions pour éviter des traces pile en cours de création.

Je pense que cette technique est justifiable si « cachée » des clients. IE, votre FlyingPig ne doit jamais être en mesure de quitter votre bibliothèque (toutes les méthodes publiques devraient garantir transitive de ne pas le jeter). Une façon de garantir que ce serait d'en faire une exception vérifiée.

Je pense que la seule justification pour l'extension Throwable est parce que vous voulez permettre aux gens de passer dans les callbacks qui ont catch (Exception e) les clauses, et que vous souhaitez que votre résultat à être ignorés par eux. Je peux acheter à peu près ça ...

L'annotation org.junit.Test comprend la classe None qui se prolonge Throwable et est utilisée comme valeur par défaut pour le paramètre d'annotation expected.

Si vous pouvez justifier ce qui distingue une FlyingPig part à la fois l'erreur et d'exception, de telle sorte qu'il ne convient pas comme une sous-classe de non plus, alors il n'y a rien de fondamentalement mauvais dans sa création.

Le plus gros problème que je peux penser est dans le monde pragmatique, parfois il y a des raisons valables pour attraper java.lang.Exception. Votre nouveau type de throwable va voler à droite des blocs try-catch passé qui avaient toutes les attentes raisonnables de supprimer (ou l'exploitation forestière, l'emballage, peu importe) tous les possibles problèmes non mortels.

A l'inverse, si vous faites l'entretien d'un ancien système qui est un java.lang.Exception, vous supprimer juste tricher pourrait autour d'elle. (En supposant que l'appel sincère pour le temps de fixer réellement est refusée à bon droit).

  

Cette question a évolué, je vois   que j'ai mal compris le point de la   question initiale, si une partie de la   D'autres réponses sont probablement plus   pertinent. Je laisserai cette réponse jusqu'à   ici, car il peut encore être utile   d'autres qui ont une question similaire,   et trouver cette page en recherchant   une réponse à leur question.

Il n'y a rien de mal à l'extension de Throwable pour pouvoir jeter (et poignée) exceptions personnalisées. Cependant, vous devez garder à l'esprit les points suivants:

  • En utilisant la plus exception spécifique possible est une excellente idée. Il permettra à l'appelant de traiter différents types d'exceptions différemment. La hiérarchie de classe de l'exception est important de garder à l'esprit, de sorte que votre exception personnalisée devrait étendre un autre type de Throwable qui est aussi proche de votre exception possible.
  • L'extension Throwable est peut-être trop haut niveau. Essayez extension Exception ou RuntimeException à la place (ou une exception au niveau inférieur qui est plus proche de la raison pour laquelle vous lancer une exception). Gardez à l'esprit la différence entre un RuntimeException et une exception.
  • Un appel à une méthode qui renvoie une exception (ou une sous-classe d'exception) devra être enveloppé dans un bloc try / catch qui est capable de faire face à l'exception. Ce qui est bon pour les cas où vous attendre que les choses vont mal, en raison de circonstances qui peuvent être hors de votre contrôle (par exemple, le réseau étant vers le bas).
  • Un appel à une méthode qui jette un RuntimeException (ou une sous-classe de celui-ci) n'a pas besoin d'être enveloppé dans un bloc try / catch qui peut gérer l'exception. (Il pourrait certainement, mais il n'a pas besoin d'être.) Ce qui est plus pour les exceptions qui ne devrait vraiment pas s'attendre.

Alors, supposons que vous avez les classes d'exception suivantes dans votre base de code:

public class Pig extends Throwable { ... }
public class FlyingPig extends Pig { ... }
public class Swine extends Pig { ... }
public class CustomRuntimeException extends RuntimeException { ... }

Et certaines méthodes

public void foo() throws Pig { ... }
public void bar() throws FlyingPig, Swine { ... }
// suppose this next method could throw a CustomRuntimeException, but it
// doesn't need to be declared, since CustomRuntimeException is a subclass
// of RuntimeException
public void baz() { ... } 

Maintenant, vous pourriez avoir un code qui appelle ces méthodes comme ceci:

try {
    foo();
} catch (Pig e) {
    ...
}

try {
    bar();
} catch (Pig e) {
    ...
}

baz();

Notez que lorsque nous appelons bar(), nous pouvons simplement prendre Pig, puisque les deux FlyingPig et Swine étendent Pig. Ceci est utile si vous voulez faire la même chose à gérer soit une exception. Vous pouvez cependant les traiter différemment:

try {
    bar();
} catch (FlyingPig e) {
    ...
} catch (Swine e) {
    ...
}
scroll top