Capturando múltiples excepciones en Java-8

71

Al probar la función de captura múltiple que encontré en mi m1()método, todo funciona bien como se esperaba.

Sin embargo, en m2()el mismo código no se compila. Acabo de cambiar la sintaxis para reducir la cantidad de líneas de código.

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

¿Por qué el método no m2()compila?

bufón
fuente
22
¿Qué error de compilación estás obteniendo?
Gavin

Respuestas:

79

El tipo de la expresión.

b ? new Excep1() : new Excep2()

es decir Exception, ya que ese es el supertipo común de Excep1y Excep2.

Sin embargo, no está capturando Exception, por lo que el compilador se queja al respecto.

Si atrapa Exception, pasará la compilación:

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

Traté de encontrar la entrada JLS que explica el tipo de expresión ternaria condicional en su ejemplo.

Todo lo que pude encontrar fue que esta expresión particular es un 15.25.3. Expresión condicional de referencia .

No estoy del todo seguro si cuenta como una expresión poli o una expresión independiente. Creo que es independiente (dado que las expresiones poli implican un contexto de asignación o un contexto de invocación, y no creo que una throwdeclaración cuente como ninguno de esos).

Para una expresión independiente: "Si el segundo y tercer operandos tienen el mismo tipo (que puede ser el tipo nulo), entonces ese es el tipo de expresión condicional".

En su caso, el segundo y el tercer operandos tienen tres tipos comunes Object, Throwabley Exceptionel tipo de la expresión debe ser uno de los dos últimos, ya que "La expresión en una instrucción throw debe denotar una variable o un valor de un tipo de referencia que es asignable (§5.2) al tipo Throwable ".

Parece que el compilador elige el tipo común más específico ( Exception) y, por lo tanto, catch (Exception e)resuelve el error de compilación.

También traté de reemplazar sus dos excepciones personalizadas con dos subclases de IOException, en cuyo caso catch (IOException e)resuelve el error de compilación.

Eran
fuente
11
@Smile, el tipo de expresión condicional ternaria debe ser común a los operandos segundo y tercero. Por lo tanto no puede ser Excep1o Excep2. Solo puede ser Exception.
Eran
2
El último punto en 15.25.3 tiene la respuesta: "De lo contrario, el segundo y tercer operandos son de los tipos S1 y S2 respectivamente. Sea T1 el tipo que resulta de aplicar la conversión de boxeo a S1, y sea T2 el tipo que resulta de aplicar la conversión de boxeo a S2. El tipo de expresión condicional es el resultado de aplicar la conversión de captura (§5.1.10) a lub (T1, T2) ". lub aquí es Least Upper Bound, que es el supertipo común más cercano que comparten los dos tipos de expresiones.
amalloy el
22

Estás confundiendo al compilador con esta línea:

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

El compilador ve que el resultado de la expresión (a la izquierda del lanzamiento) es la superclase común entre Except1 y Except2, que es Exception y, por lo tanto, el tipo efectivo que está lanzando se convierte en Exception. La instrucción catch no puede detectar que está intentando lanzar Excep1 o Except2.

GideonleGrange
fuente
4

Java lo restringe para capturar o declarar todos los tipos de excepción que el método puede generar,

Busca padre común para ambas (/ todas) Excepciones y espera que atrape o declare como tiros, por ejemplo si Excep1 extiende Throwabletendrás que atrapar también Lanzable

En el primer caso, Java está seguro de que estás lanzando Excep1oExcep2

usuario7294900
fuente