7
votes

Plusieurs captures spécifiques ou une attrape tout cela?

J'ai vu ce sujet surgir parfois dans le passé, mais même après Googling À ce sujet , je ne peux toujours pas comprendre ce qui serait une bonne et élégante façon de faire face à cela, alors c'est ici.

Dis que j'ai du code qui jette différentes exceptions ... xxx pré>

... et comme nous pouvons le constater, je saisis ces exceptions et jette un nouveau dit que quelque chose s'est mal passé dans mon API. P>

Ceci Il me semble un code trop répétitif, il suffit donc d'attraper un type d'exception et de gérer l'envelopper et de lancer une nouvelle. p> xxx pré>

Dans ce cas, il reste bien plus simple, Mais la chose est que nous serions également attraper toutes les runtimédies. Compte tenu de cela, nous pourrions attraper-re-jeter la runtimédiexception afin que nous puissions éviter cela. P> xxx pré>

c'est un peu volumineux mais cela fait l'affaire. Maintenant, il y a maintenant un autre petit problème sur la capture (exception e), que si mon API intérieur jette une autre myapIexception, elle serait également prise, enveloppée et jetée dans une autre myapIexception. Dans ce cas particulier, nous pourrions aussi attraper MyAPIException et le jeter. P>

try {
  /* some code that throws some exceptions */
} catch (RuntimeException e) {
    throw e;
} catch (MyAPIException e) {
    throw e;
} catch (Exception e) {
    throw new MyAPIException("Something went wrong", e);
}


0 commentaires

6 Réponses :


2
votes

avoir plus d'un myapiException . Si vous avez toutes les exceptions comme MyAPIException , il devient un peu difficile pour vous et pour les autres aussi à lire votre code. Nommer cela correctement serait aussi crucial. De plus, vous ne voulez pas toujours attraper et retirez-le. Si tel est le cas, déclarez simplement un lance dans la signature de méthode.

Plus, vous ne pouvez pas résoudre l'une des captures simples ou plusieurs captures. C'est plus d'une décision de jugement imo car il existe des exceptions qui sont fatales (comme dans l'ensemble du programme, doivent arrêter) à des types plus faciles à manipuler.

Je ne vois rien de mal au tout lorsque vous avez un tas de lancers des clauses dans votre API. C'est une implémentation beaucoup plus chère. Alors, que si l'appelant doit gérer les exceptions que vous avez définies. Si une méthode dans votre API peut lancer une exception et que quelque chose doit être fait à ce sujet, l'appelant doit alors avoir à le gérer. Quoi qu'il en soit, votre documentation de cette exception particulière doit être claire afin de ne pas confondre l'appelant.

Un facteur supplémentaire qui décide que c'est la complexité de l'API. Parfois, j'avais écrit une API qui était modérément complexe et je devais faire face aux mêmes problèmes comme celui que vous avez présenté. J'avais écrit quelques exceptions personnalisées pour quelques méthodes. Je suis sûr que vous ne finirez pas de jeter des exceptions pour toute la méthode publique que l'API expose, mais il existe des endroits qu'ils sont inévitables.

Enfin, si vous sentez avoir trop d'exceptions personnalisées, un choix amer, vous pouvez avoir une seule exception avec des codes d'erreur clairement documentés. De cette façon, l'appelant peut gérer l'exception et traiter les codes d'erreur car il voit en forme.


3 commentaires

La chose est si je commence simplement à jeter toutes les autres exceptions, quelqu'un d'autre devrait faire face à toutes ces exceptions et je ne pense pas que c'est très agréable d'avoir une méthode qui jette de nombreux types d'exceptions. De plus, si je devais avoir un type d'exception à chaque exception enveloppée, ce serait simplement idiot ... pourquoi pas simplement le jeter? (Et maintenant nous avons une récursion)


Eh bien, dans ce cas, je veux juste le montrer à l'utilisateur de cette API que quelque chose a mal tourné et qu'il ne pouvait pas être terminé, il peut y faire face à cela dans un simple bloc de capture (capture (myapiException e)) au lieu d'attraper Plusieurs types d'exceptions ou devoir faire face à ce même problème de capture présenté ici. Si l'utilisateur souhaitait connaître la raison pour laquelle il a échoué, il peut toujours regarder la cause à l'intérieur de l'exception. Je pense que quelque chose comme ça serait un moyen d'API Natre, mais comme vous l'avez dit, cela pourrait être une décision de jugement. Des pensées?


Comme vous l'avez souligné, nous pourrions également avoir beaucoup d'exceptions spécifiques pour chaque cas, mais l'OMI, il serait sage de rendre toutes ces exceptions s'étendre d'une seule exception dans votre API. Comme ceci, l'utilisateur pouvait gérer chaque cas (captures spécifiques) ou une prenant tout (prenez l'exception principale d'API) en fonction de ses besoins.



2
votes

en Java 7, vous pourrez faire quelque chose comme

try {
  /* some code that throws these exceptions */
} catch (NoSuchAuthorityCodeException , FactoryException, MismatchedDimensionException , TransformException e) {
    throw new MyAPIException("Something went wrong", e);
}


1 commentaires

Ouais, j'en ai entendu parler, mais la chose est, à l'entreprise que je travaille, nous utilisons toujours Java5 (!!!), et j'aimerais faire quelque chose d'élégant au sein de Java5 ou Java6 pour la question



5
votes

Depuis que vous êtes coincé avec Java5 et que vous utilisez une exception exclusive, pourquoi ne pas mettre toute cette logique d'exception dans la classe d'exception.

USEAGE P>

class MyAPIException extends Exception
{
    private MyAPIException ( String message , Throwable cause ) { super ( message , cause ) ; }

    private static void myAPIException ( Exception cause ) throws MyAPIException
    {
         throw new MyAPIException ( "Something Went Wrong" , cause ) ;
    }

    public static void handle ( Exception e ) throws MyAPIException
    {
          try
          {
               throw ( e ) ;
          }
          catch ( RuntimeException cause )
          {
                throw cause ;
          }
          catch ( MyAPIException cause )
          {
                 throw cause ;
          }
          catch ( NoSuchAuthorityCodeException cause )  // repeat for other exceptions
          {
                 myAPIException ( cause ) ;
          }
          catch ( Exception cause ) // this should not happen
          {
                  assert false ; // or log it or throw a RuntimeException ... somehow signal that programming logic has failed
          }
    }
}


7 commentaires

Je ne veux vraiment pas attraper la runtimédiexception et l'apiezexception


Ce serait bien si vous mettez un exemple d'utilisation.


@Pablo Cabrera J'ai ajouté un exemple d'utilisation. Il lancera la runtimédiexception et la myapIexception. Je mettais tout la méthode statique S dans la classe MyAPIException. Vous pouvez appeler cela de votre code avec un simple essai / attraper.


+1. Je ne pense pas que ce soit la meilleure solution, mais c'est une approche très intéressante.


Ce n'est pas très flexible ... Et si je voudrais jeter cette exception sur un autre contexte (ce que je fais)? Devrais-je gérer ces autres exceptions aussi? Devrais-je coder une "poignée" spécifique pour chaque utilisation?


@Pablo Cabrera Si vous gérez toujours des exceptions de la même manière, vous pouvez utiliser une méthode (par exemple la poignée) pour le faire - éliminer le code dupliqué. Modifiez la méthode de la poignée donnée en ajoutant des blocs de capture pour toutes les exceptions que vous souhaitez prendre en charge. Si vous ne gérez pas toujours des exceptions de la même manière, cela est moins utile.


@emory, mais j'aurais alors le même nombre de "captures" que j'avais dans le premier exemple ...



0
votes

Tout dépend de ce que vous voulez faire. Si tout ce que vous voulez faire, c'est lancer une nouvelle myException ("quelque chose mal tourné", e); puis une capture tout va faire.


1 commentaires

Comme je l'ai dit auparavant, je ne veux pas attraper runtimédiexception ou myapIexception ... RTFQ



1
votes

Ok gars, voici ce que je suis venu avec ... ce n'est pas si élégant mais je pense que c'est un peu mieux que d'avoir diverses captures.

Tout d'abord, nous avons une classe abstraite appelée ExceptionnelHandler forte >. P>

try {
  /* some code that throws these exceptions */
} catch (Exception e) {
    new ExceptionHandler<MyAPIException>() {
        @Override
        protected void handler(Throwable t) throws MyAPIException {
            throw new MyAPIException("Something went wrong", t);
        }
    }.
        catches(MismatchedDimensionException.class).
        catches(NoSuchAuthorityCodeException.class).
        catches(FactoryException.class).
        catches(TransformException.class).
        handle(e);
    return null;
}


3 commentaires

L'idée est très bonne. (1) Utilisez ISAssignABLEDFROM au lieu d'IsInstance de. (2) Je ne comprends pas vraiment la méthode GetGenericClass. Je pense que ce serait plus propre de la classe Exceptionnel Herdler juste pour avoir une instance de classe . (3) Si vous utilisez un cadre d'exploitation forestière, vous pouvez peut-être ajouter une instruction de journalisation BTWN Handler (T) et retour - cela vous aidera à utiliser en cas de manutention (t) mange à tort une exception importante. (4) Si vous faites la classe exceptionnelle immuable, je pense que la programmation et le débogage seront plus faciles - il n'est pas nécessaire de deviner les exceptions qu'il gère à un moment donné.


(5) Remplacez le non gré par «ASSTERTE FAUX:« Exception non confondue »;« Je n'aime pas le non-fiancé ». Si l'exceptionnelle doit être instanciée correctement, il ne devrait pas y avoir de pas de non pas. La présence de la non-andhandexception indique donc une erreur de programmation.


Maintenant, je pense que je comprends mieux ce que tu veux. Donc, j'ai une autre réponse ci-dessous.



0
votes

ci-dessous est une autre approche et un exemple d'utilisation. La classe MyAPIException a une méthode de la poignée. La méthode de la poignée traitera toute exception.

  1. Si l'exception est une exception exécutable ou une myapIxception, la poignée le jettera sans l'envelopper. Li>
  2. Sinon, la méthode de la poignée testera si des affirmations sont activées. Si des assertions sont activées, la méthode de la poignée testera pour voir si l'exception est assignable de l'une des types d'exception pris en charge, en lançant une AssertionError s'il n'est pas assignable. (Si les assertions ne sont pas activées, la méthode de la poignée ignore le paramètre Types d'exception pris en charge.) Li>
  3. Enfin - s'il atteint ce point - la méthode de la poignée enveloppera l'exception dans une exception myapiException et jetez-la. Li> ol>

    Lorsque vous testez votre code, exécutez-le avec des assertions activées. En production, exécutez-la avec des assertions désactivées. P>

    Si vous utilisez cette technique, vous devrez tester des erreurs que le compilateur aurait autrement pris autrement. SOAPBOX> P>

    class Usage
    {
        public static void main ( String [ ] args ) throws MyAPIException
        {
        try
            {
            switch ( Integer . parseInt ( args [ 0 ] ) )
                {
                case 1 :
                throw new RuntimeException ( ) ;
                case 2 :
                throw new SQLException ( ) ;
                case 3 :
                throw new MyAPIException ( null ) ;
                case 4 :
                throw new IOException ( ) ;
                }
            }
        catch ( Exception cause )
            {
            System . out . println ( cause . getMessage ( ) ) ;
            System . out . println ( cause . getCause ( ) ) ;
            MyAPIException . handle ( cause , IOException . class ) ;
            }
        }
    }
    


0 commentaires