Question

Je pense que Exception.fillInStackTrace devrait Exception ou dérivés objets d'exception. Compte tenu des deux fonctions ci-dessous,

public static void f() throws Throwable {
    try {
        throw new Throwable();
    } catch (Exception e) {
        System.out.println("catch exception e");
        e.printStackTrace();
    } 
}
public static void g() throws Throwable {
    try {
        try {
            throw new Exception("exception");
        } catch (Exception e) {
            System.out.println("inner exception handler");
            throw e.fillInStackTrace();
        }
    } catch (Exception e) {
        System.out.println("outer exception handler");
        e.printStackTrace();
    }
}
  1. Le exception handler ne pouvait pas attraper le new Throwable() dans la première fonction f().
  2. Le exception handler pourrait prendre le e.fillInstackTrace() dans la seconde fonction g().
  3. Mais la deuxième fonction g() aurait encore besoin de throws Throwable. Ceci est vraiment étrange, puisque nous pourrions attraper e.fillInstackTrace().

Alors, ma question est pourquoi ne pas Exception.fillInStackTrace Exception ou exception dérivée au lieu de développer une telle syntaxe étrange?

EDIT :
clarifier ma question: Qu'est-ce que je veux dire par "syntaxe étrange" sont

  1. Comme référence Exception.fillInStackTrace() retour Throwable, le gestionnaire d'exception qui recieve référence Exception ne devrait pas être en mesure d'attraper le java exception.Because ne permet pas implict baissés, il devrait être quelque chose comme return (Exception)e.fillInstackTrace().
  2. Étant donné qu'il est que le gestionnaire d'exception recieving référence Exception pourrait gérer l'exception de Throwable, il n'y a pas besoin de marquer la méthode g() lance compilateur Throwable exception.But java ne nous appliquer à le faire.

merci.

Était-ce utile?

La solution

Il est effectivement plus facile de répondre à vos questions en commençant par la question 2.

Vous avez demandé:    2. Étant donné qu'il est que le gestionnaire d'exception recieving référence d'exception pourrait gérer l'exception Throwable, il n'y a pas besoin de marquer le g () méthode lance compilateur java Throwable exception.But ne nous appliquer à le faire.

Réponse: En fait, catch (Exception e) ne peut pas attraper un Throwable. Essayez ceci:

try {
       Throwable t = new Throwable();
       throw t.fillInStackTrace();
} catch (Exception e) {
    System.out.println("outer exception handler");
    e.printStackTrace();
} 

Vous verrez que la clause catch ne coud pas le jeter dans ce cas.

La raison pour laquelle la méthode clause de capture fonctionne dans votre g () est que lorsque vous invoquez throw e.fillInStackTrace(), l'appel à fillInStackTrace retourne en fait une exception (c'est parce que e est une exception lui-même). Étant donné que l'exception est une sous-classe de Throwable, qui ne contredit pas la déclaration de fillInStackTrace.

Passons maintenant à la première question

Vous avez demandé:    1. Depuis Exception.fillInStackTrace () retourne référence Throwable, le gestionnaire d'exception qui recieve référence d'exception ne devrait pas être en mesure d'attraper le java exception.Because ne permet pas implict baissés, il devrait être quelque chose comme retour (Exception) e.fillInstackTrace () .

Réponse: Ce n'est pas exactement un démoralisé implicite. Pensez à cela comme une variation de surcharge.

Disons que vous avez

void process(Throwable t){
   ...
}
void process(Exception e){
  ...
} 

Si vous appelez process(someObject), il sera déterminé lors de l'exécution si la première ou la deuxième méthode de processus est appelé. De même, si le catch (Exception e) clause peut reprendre votre jet sera déterminé lors de l'exécution, selon que vous jetez une exception ou Throwable.

Autres conseils

Je suis un peu perplexe par votre question. Il y a clairement quelque chose au sujet des exceptions java / gestion des exceptions que vous ne comprenez pas. permet donc commencer au début.

En Java, toutes les exceptions (dans le sens où ce terme est utilisé dans la spécification du langage Java) sont des exemples d'une certaine classe qui est une sous-classe de java.lang.Throwable. Il y a deux (et seulement deux) sous-classes directes de Throwable; à savoir java.lang.Exception et java.lang.Error. Les cas de toutes ces classes ... y compris les cas de Throwable et erreur ... sont appelées exceptions dans le JLS.

Un gestionnaire d'exception attire des exceptions (au sens JLS) qui sont compatibles avec l'affectation du type d'exception utilisé dans la déclaration de catch. Ainsi, par exemple:

try {
    ....
} catch (Exception ex) {
    ...
}

va attraper toute exception levée dans le bloc de try qui est une instance de java.lang.Exception ou d'un sous-type direct ou indirect de java.lang.Exception. Mais il ne sera pas attraper une instance de java.lang.Throwable, parce que c'est (évidemment) pas l'un des ci-dessus.

Par contre:

try {
    ....
} catch (Throwable ex) {
    ...
}

attraper une instance de java.lang.Throwable.

Revoir votre exemple à la lumière de cela, il est évident pourquoi la méthode f ne rattrape pas l'instance Throwable: il ne correspond pas au type d'exception dans la clause catch! En revanche, dans la méthode g l'instance d'exception correspond au type d'exception dans la clause de capture et est donc pris.

Je ne comprends pas ce que vous dites au sujet besoin de jeter un Throwable dans g. Tout d'abord, le fait que la méthode déclare qu'il jette Throwable ne pas signifie qu'il a réellement besoin de le jeter. Tout ce qu'il dit est qu'il peut jeter quelque chose assignable à throwable ... peut-être dans une version future de la méthode de g. En second lieu, si vous deviez ajouter throw e; au bloc catch externe, il serait être jeter quelque chose qui est assignable à Throwable.

Enfin, il est généralement une mauvaise idée à la création d'instances de Throwable, Exception, erreur et RuntimeException. Et vous devez être très prudent quand et comment vous les attraper. Par exemple:

try {
     // throws an IOException if file is missing
    InputStream is = new FileInputStream("someFile.txt");
    // do other stuff
} catch (Exception ex) {
    System.err.println("File not found");
    // WRONG!!!  We might have caught some completely unrelated exception;
    // e.g. a NullPointerException, StackOverflowError, 
}

EDIT - dans les commentaires OP de réponse:

  

Mais ce que je jette avec un jet e.fillInStackTrace (); devrait être un intance de Throwable, pas d'exception!

Le Javadoc dit expressément que l'objet retourné est l'objet d'exception que vous appelez la méthode sur. Le but de la méthode de fillInStacktrace() consiste à remplir la trace de pile pour un objet existant. Si vous voulez une autre exception, vous devez utiliser new pour créer un.

  

En fait, je veux dire le gestionnaire d'exception outter ne devrait pas prendre le Throwable jeté par un jet e.fillInStackTrace ().

Je l'ai expliqué pourquoi elle le fait - parce que le Throwable est en fait l'exception d'origine. Y at-il quelque chose au sujet de mon explication que vous ne comprenez pas ou êtes-vous simplement dire que vous ne voulez pas la façon que Java est défini?

EDIT 2

  

Et si le gestionnaire d'exception outter pourrait gérer l'exception Throwable, pourquoi devons-nous préciser que la méthode g jetterait exception Throwable

Vous ne comprenez pas ce que je disais ... ce qui était que si vous ne jetez une exception, le throws Throwable ne serait pas redondant. OTOH, je pense enfin que je comprends votre plainte.

Je pense que le point crucial de votre plainte est que vous obtiendrez une erreur de compilation avec ceci:

public void function() throws Exception {
    try {
        throw new Exception();
    } catch (Exception ex) {
        throw ex.fillInStackTrace();
        // according to the static type checker, the above throws a Throwable
        // which has to be caught, or declared as thrown.  But we "know" that the 
        // exception cannot be anything other than an Exception.
    }
}

Je vois que cela est quelque peu inattendu. Mais il est inévitable que j'ai peur. Il n'y a aucun moyen (à court d'un changement majeur au système de type Java) que vous pouvez déclarer signature du fillInStacktrace qui fonctionnera dans tous les cas. Par exemple, si vous avez déplacé la déclaration de la méthode à la classe d'exception, vous devriez juste répéter le même problème avec les sous-types d'exception. Mais si vous avez essayé d'exprimer la signature à l'aide d'un paramètre de type générique, il impliquerait toutes les sous-classes de faire des types génériques explicites Throwable.

Heureusement, le remède est très simple; jeter le résultat de fillInStacktrace() comme suit:

public void function() throws Exception {
    try {
        throw new Exception();
    } catch (Exception ex) {
        throw (Exception) (ex.fillInStackTrace());
    }
}

Le dernier point est qu'il est très inhabituel pour une application d'appeler explicitement fillInStacktrace(). A la lumière de cela, il aurait tout simplement pas été utile pour les concepteurs de Java d'avoir « Busted leurs tripes » essayer de résoudre ce problème. D'autant plus que c'est vraiment un inconvénient mineur ... au plus.

Je pense que vous devriez demander Frank Yellin (le @author de java.lang.Exception). Comme d'autres l'ont dit, fillInStackTrace() est déclaré dans Throwable et documenté pour revenir this, de sorte que son type de retour doit être Throwable. Il est juste hérité par Exception. Frank aurait pu en Exception substituée, comme ceci:

public class Exception extends Throwable{
    /**Narrows the type of the overridden method*/
    @Override
    public synchronized Exception fillInStackTrace() {
        super.fillInStackTrace();
        return this;
    }
}

... mais il ne l'a pas. Avant Java 1.5, la raison est qu'il aurait produit une erreur de compilation. Dans la version 1.5 et au-delà, Covariant types de retour sont autorisés et est au-dessus juridique.

Mais je suppose que si la dérogation ci-dessus existait, vous auriez alors se demander pourquoi RuntimeException ne dispose pas d'une dérogation similaire, pourquoi ArrayStoreException ne remplace pas override, et ainsi de suite. Alors Frank et les amis probablement ne voulaient pas écrire ces centaines de remplacements identiques.

Il convient de noter que, si vous traitez avec vos propres classes d'exception personnalisée, vous pouvez facilement remplacer la méthode de fillinStackTrace() comme je l'ai fait ci-dessus, et obtenir le type plus étroit que vous êtes après.

L'utilisation des génériques, on pourrait imaginer augmenter la déclaration de Throwable à:

public class Throwable<T extends Throwable<T>>{
    public synchronized native T fillInStackTrace();
}

... mais ce n'est pas vraiment satisfaisante, pour des raisons qui dépassent la portée de cette réponse.

fillInStackTrace renvoie la référence au même objet. Il est procédé de chaînage pour permettre la re-jeter Exception et remettre à zéro la trace de pile d'exception.

public static void m() {
    throw new RuntimeException();

}

public static void main(String[] args) throws Throwable {
    try {
        m();
    } catch (Exception e) {
        e.printStackTrace();
        throw e.fillInStackTrace();
    }
}

Le type de retour de la méthode ne peut être de type base qui est Throwable. Il peut être generified de telle sorte que la méthode renvoie le type paramétré. Mais ce n'est pas le cas pour l'instant.

RuntimeException e = new RuntimeException();
Throwable e1 = e.fillInStackTrace();
System.out.println(e1.getClass().getName()); //prints java.lang.RuntimeException
System.out.println(e == e1); //prints true

fillInStackTrace() est défini par Throwable, non Exception.

Toutes les sous-classes de Throwable sont des exceptions (Error, par exemple). En ce qui Throwable concerne, la seule chose qu'il peut garantir à la valeur de retour de fillInStackTrace() est qu'il est une instance de Throwable (puisqu'il retourne juste le même objet, comme Chandra Patni noté).

En fait fillInStackTrace retourne le même objet, il a été invoqué sur.

e.fillInStackTrace == e est toujours vrai

Il est juste un raccourci , vous pouvez aussi simplement écrire

    } catch (Exception e) {
        System.out.println("inner exception handler");
        e.fillInStackTrace();
        throw e;
    }

ou utiliser un plâtre

    throw (Exception) e.fillInStackTrace();

BTW, la même chose se produit avec initCause().

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top