Łapanie wielu wyjątków w Javie-8

71

Podczas wypróbowania funkcji Multi-catch znalazłem w mojej m1()metodzie wszystko działa dobrze zgodnie z oczekiwaniami.

Jednak w m2()tym samym kodzie nie kompiluje się. Właśnie zmieniłem składnię, aby zmniejszyć liczbę wierszy kodu.

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

Dlaczego metoda się nie m2()kompiluje?

Żartowniś
źródło
22
Jaki masz błąd kompilacji?
Gavin

Odpowiedzi:

79

Rodzaj wyrażenia

b ? new Excep1() : new Excep2()

jest Exception, ponieważ jest to powszechny nadtyp Excep1i Excep2.

Jednak nie łapiesz Exception, więc kompilator narzeka na to.

Jeśli złapiesz Exception, przejdzie kompilacja:

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

Próbowałem znaleźć wpis JLS, który wyjaśnia typ warunkowego wyrażenia trójskładnikowego w twoim przykładzie.

Wszystko, co mogłem znaleźć, to to, że to konkretne wyrażenie to 15.25.3. Odwołanie Wyrażenie warunkowe .

Nie jestem do końca pewien, czy liczy się ono jako wyrażenie poli czy samodzielne. Wydaje mi się, że jest samodzielny (ponieważ wyrażenia poli obejmują kontekst przypisania lub kontekst wywołania, i nie sądzę, aby throwoświadczenie liczyło się jako jedno z nich).

W przypadku samodzielnego wyrażenia: „Jeśli drugi i trzeci operand mają ten sam typ (który może być typem pustym), to jest to typ wyrażenia warunkowego”.

W twoim przypadku, drugi i argumenty trzecie mają trzy podstawowe rodzaje - Object, Throwablei Exception- rodzaj ekspresji musi być jednym z dwóch ostatnich, ponieważ „The Expression w oświadczeniu rzutów musi albo oznacza zmienną lub wartość typu referencyjnego który można przypisać (§5.2) do typu Throwable. ”

Wygląda na to, że kompilator wybiera najbardziej typowy typ ( Exception), a zatem catch (Exception e)rozwiązuje błąd kompilacji.

Próbowałem również zastąpić dwa niestandardowe wyjątki dwiema podklasami IOException, w którym to przypadku catch (IOException e)rozwiązuje błąd kompilacji.

Eran
źródło
11
@Smile typ trójskładnikowego wyrażenia warunkowego musi być wspólny dla drugiego i trzeciego operandu. Dlatego nie może być Excep1lub Excep2. Może być tylko Exception.
Eran
2
Ostatni punkt w 15.25.3 ma odpowiedź: „W przeciwnym razie drugi i trzeci operand są odpowiednio typu S1 i S2. Niech T1 będzie typem wynikającym z zastosowania konwersji boksu do S1, i niech T2 będzie typem, który daje wynik od zastosowania konwersji boksu do S2. Typ wyrażenia warunkowego jest wynikiem zastosowania konwersji przechwytywania (§5.1.10) do lub (T1, T2). ” lub tutaj jest Least Upper Bound, który jest najbliższym wspólnym nadtypem, który dzielą typy obu wyrażeń.
amalloy
22

Mylisz kompilator z tą linią:

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

Kompilator widzi, że wynikiem wyrażenia (po lewej stronie rzutu) jest wspólna superklasa między Except1 i Except2, czyli Exception, a zatem rzucany przez ciebie typ efektywny staje się Exception. Instrukcja catch nie może wykryć, że próbujesz wyrzucić Excep1 lub Except2.

GideonleGrange
źródło
4

Java ogranicza przechwytywanie lub deklarowanie wszystkich typów wyjątków, które metoda może zgłaszać,

To poszukiwanie wspólnych zarówno dla rodzica (/) Wyjątki i wszyscy oczekują, aby złapać albo uznać jako rzuca, na przykład jeśli Excep1rozciąga Throwabletrzeba będzie złapać także Throwable

W pierwszym przypadku Java jest pewna, że ​​rzucasz Excep1lubExcep2

użytkownik7294900
źródło