Mehrere Ausnahmen in Java-8 abfangen

71

Beim Ausprobieren der Multi-Catch- Funktion habe ich in meinem gefundenm1() Methode , funktioniert alles wie erwartet.

Im m2()selben Code wird jedoch nicht kompiliert. Ich habe gerade die Syntax geändert, um die Anzahl der Codezeilen zu reduzieren.

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 {
    }
}

Warum m2()kompiliert die Methode nicht ?

Joker
quelle
22
Welchen Kompilierungsfehler erhalten Sie?
Gavin

Antworten:

79

Die Art des Ausdrucks

b ? new Excep1() : new Excep2()

ist Exception, da dies der übliche Supertyp von Excep1und ist Excep2.

Da Sie jedoch nicht fangen Exception, beschwert sich der Compiler darüber.

Wenn Sie fangen Exception, wird es die Kompilierung bestehen:

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

Ich habe versucht, den JLS-Eintrag zu finden, der die Art des bedingten ternären Ausdrucks in Ihrem Beispiel erklärt.

Ich konnte nur feststellen, dass dieser spezielle Ausdruck ein 15.25.3 ist. Referenzbedingter Ausdruck .

Ich bin mir nicht ganz sicher, ob es sich um einen Polyausdruck oder einen eigenständigen Ausdruck handelt. Ich denke, es ist eigenständig (da Poly-Ausdrücke einen Zuweisungskontext oder einen Aufrufkontext beinhalten, und ich denke nicht, dass athrow Anweisung als zählt).

Für einen eigenständigen Ausdruck: "Wenn der zweite und der dritte Operand denselben Typ haben (der möglicherweise der Nulltyp ist), ist dies der Typ des bedingten Ausdrucks."

In Ihrem Fall haben die zweite und dritte Operanden drei Arten - Object, Throwableund Exception- die Art des Ausdrucks einer der beiden letzteren sein muß, da „Der Ausdruck in einer throw - Anweisung entweder eine Variable oder Wert eines Referenztypen bezeichnen muss welches dem Typ Throwable zuweisbar ist (§5.2). "

Es scheint, dass der Compiler den spezifischsten allgemeinen Typ ( Exception) catch (Exception e)auswählt und daher den Kompilierungsfehler löst.

Ich habe auch versucht, Ihre beiden benutzerdefinierten Ausnahmen durch zwei Unterklassen von zu ersetzen. IOExceptionIn diesem Fall wird catch (IOException e)der Kompilierungsfehler behoben.

Eran
quelle
11
@Smile Der Typ des ternären bedingten Ausdrucks muss sowohl dem 2. als auch dem 3. Operanden gemeinsam sein. Daher kann es nicht sein Excep1oder Excep2. Es kann nur sein Exception.
Eran
2
Der letzte Aufzählungspunkt in 15.25.3 hat die Antwort: "Andernfalls sind der zweite und der dritte Operand vom Typ S1 bzw. S2. Sei T1 der Typ, der sich aus der Anwendung der Boxkonvertierung auf S1 ergibt, und sei T2 der Typ, der sich ergibt Der Typ des bedingten Ausdrucks ist das Ergebnis der Anwendung der Capture-Konvertierung (§5.1.10) auf lub (T1, T2). " lub ist hier Least Upper Bound, der nächste gemeinsame Supertyp, den die Typen der beiden Ausdrücke gemeinsam haben.
Amalloy
22

Sie verwechseln den Compiler mit dieser Zeile:

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

Der Compiler sieht, dass das Ergebnis des Ausdrucks (links vom Wurf) die gemeinsame Superklasse zwischen Except1 und Except2 ist, bei der es sich um Exception handelt. Daher wird der effektive Typ, den Sie auslösen, zu Exception. Die catch-Anweisung kann nicht erkennen, dass Sie versuchen, Excep1 oder Except2 zu werfen.

GideonleGrange
quelle
4

Java beschränkt Sie darauf, alle Ausnahmetypen abzufangen oder zu deklarieren, die diese Methode auslösen kann.

Es sucht nach einem gemeinsamen Elternteil für beide (/ alle) Ausnahmen und erwartet, dass Sie Würfe fangen oder als Würfe deklarieren. Wenn Sie beispielsweise Excep1verlängern, müssen ThrowableSie auch Throwable fangen

Im ersten Fall ist Java sicher, dass Sie entweder werfen Excep1oderExcep2

user7294900
quelle