Attraper plusieurs exceptions dans Java-8

71

En essayant la fonction multi-catch que j'ai trouvée dans ma m1()méthode, tout fonctionne bien comme prévu.

Cependant, dans m2()le même code ne compile pas. Je viens de changer la syntaxe pour réduire le nombre de lignes de code.

public class Main {

    public int m1(boolean bool) {
        try {
            if (bool) {
                throw new Excep1();
            }
            throw new Excep2();
            //This m1() is compiling  abs fine.
        } catch (Excep1 | Excep2 e) {
            return 0;
        }
    }

    public int m2(boolean b) {
        try {
            throw b ? new Excep1() : new Excep2();
            //This one is not compiling.
        } catch (Excep1 | Excep2 e) {
            return 0;
        }
    }

    private static interface I {
    }

    private static class Excep1 extends Exception implements I {
    }

    private static class Excep2 extends Exception implements I {
    }
}

Pourquoi la méthode ne m2()compile- t-elle pas ?

Joker
la source
22
Quelle erreur de compilation obtenez-vous?
Gavin

Réponses:

79

Le type de l'expression

b ? new Excep1() : new Excep2()

est Exception, puisque c'est le supertype commun de Excep1et Excep2.

Cependant, vous n'attrapez pas Exception, donc le compilateur s'en plaint.

Si vous attrapez Exception, il passera la compilation:

public int m2(boolean b) {
    try {
        throw b ? new Excep1() : new Excep2();
    } catch (Exception e) {
        return 0;
    }
}

J'ai essayé de trouver l'entrée JLS qui explique le type d'expression ternaire conditionnelle dans votre exemple.

Tout ce que j'ai pu trouver, c'est que cette expression particulière est un 15.25.3. Expression conditionnelle de référence .

Je ne suis pas tout à fait sûr si cela compte comme une expression poly ou une expression autonome. Je pense que c'est autonome (puisque les expressions poly impliquent un contexte d'affectation ou un contexte d'invocation, et je ne pense pas qu'une throwdéclaration compte pour l'un ou l'autre).

Pour une expression autonome: "Si les deuxième et troisième opérandes ont le même type (qui peut être le type nul), alors c'est le type de l'expression conditionnelle."

Dans votre cas, les deuxième et troisième opérandes ont trois types communs - Object, Throwableet Exception- le type de l'expression doit être l'un des deux derniers, car "l'expression dans une instruction throw doit soit désigner une variable soit une valeur d'un type de référence qui est assignable (§5.2) au type Throwable. "

Il semble que le compilateur sélectionne le type commun le plus spécifique ( Exception), et donc catch (Exception e)résout l'erreur de compilation.

J'ai également essayé de remplacer vos deux exceptions personnalisées par deux sous-classes de IOException, auquel cas cela catch (IOException e)résout l'erreur de compilation.

Eran
la source
11
@Smile, le type de l'expression conditionnelle ternaire doit être commun aux 2e et 3e opérandes. Il ne peut donc pas être Excep1ou Excep2. Cela ne peut être que Exception.
Eran
2
La dernière puce du 15.25.3 a la réponse: "Sinon, les deuxième et troisième opérandes sont de types S1 et S2 respectivement. Soit T1 le type qui résulte de l'application de la conversion de boxe en S1, et soit T2 le type qui en résulte d'appliquer la conversion de boxe à S2. Le type de l'expression conditionnelle est le résultat de l'application de la conversion de capture (§5.1.10) à lub (T1, T2). " lub ici est Least Upper Bound, qui est le supertype commun le plus proche que les types des deux expressions partagent.
amalloy
22

Vous confondez le compilateur avec cette ligne:

throw b ? new Excep1() : new Excep2();

Le compilateur voit que le résultat de l'expression (à gauche du lancer) est la super classe commune entre Except1 et Except2, qui est Exception, et donc le type effectif que vous lancez devient Exception. L'instruction catch ne peut pas détecter que vous essayez de lancer Excep1 ou Except2.

GideonleGrange
la source
4

Java vous restreint pour intercepter ou déclarer tous les types d'exceptions que la méthode peut lancer,

Il recherche pour parent commun pour les deux (/) toutes les exceptions et vous vous attendez à attraper ou Déclarons ce qui jette, par exemple , si Excep1étend Throwablevous devrez attraper aussi Throwable

Dans le premier cas, Java est sûr que vous lancez Excep1ouExcep2

user7294900
la source