Capturando Várias Exceções no Java-8

71

Ao experimentar o recurso de captura múltipla, encontrei no meu m1()método que tudo está funcionando bem como esperado.

No entanto, no m2()mesmo código não compila. Acabei de alterar a sintaxe para reduzir o número de linhas 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 que o método não m2()compila?

Palhaço
fonte
22
Que erro de compilação você está recebendo?
Gavin

Respostas:

79

O tipo da expressão

b ? new Excep1() : new Excep2()

é Exception, já que esse é o supertipo comum de Excep1e Excep2.

No entanto, você não está entendendo Exception, então o compilador reclama disso.

Se você pegar Exception, ele passará a compilação:

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

Tentei encontrar a entrada JLS que explica o tipo de expressão ternária condicional no seu exemplo.

Tudo o que pude encontrar foi que essa expressão em particular é uma 15.25.3. Expressão Condicional de Referência .

Não tenho muita certeza se isso conta como expressão poli ou expressão independente. Eu acho que é autônomo (uma vez que as expressões polifônicas envolvem um contexto de atribuição ou de invocação, e não acho que uma throwdeclaração seja considerada uma dessas).

Para uma expressão autônoma: "Se o segundo e o terceiro operando tiverem o mesmo tipo (que pode ser o tipo nulo), esse é o tipo da expressão condicional."

No seu caso, o segundo e operandos terceiros têm três tipos comuns - Object, Throwablee Exception- o tipo de expressão deve ser um dos dois últimos, uma vez que, "A expressão em uma instrução throw ou deve denotar uma variável ou o valor de um tipo de referência que é atribuível (§5.2) ao tipo Throwable ".

Parece que o compilador escolhe o tipo comum mais específico ( Exception) e, portanto, catch (Exception e)resolve o erro de compilação.

Também tentei substituir suas duas exceções personalizadas por duas subclasses de IOException, nesse caso, catch (IOException e)resolve o erro de compilação.

Eran
fonte
11
@ Sorria, o tipo da expressão condicional ternária deve ser comum aos 2º e 3º operandos. Portanto, não pode ser Excep1ou Excep2. Só pode ser Exception.
Eran
2
O ponto final em 15.25.3 tem a resposta: "Caso contrário, o segundo e o terceiro operandos são do tipo S1 e S2, respectivamente. Seja T1 o tipo que resulta da aplicação da conversão de boxe em S1 e T2 seja o tipo que resulta de aplicar a conversão de boxe para S2. O tipo da expressão condicional é o resultado da aplicação da conversão de captura (§5.1.10) em lub (T1, T2). " lub aqui é Menor limite superior, que é o supertipo comum mais próximo que os tipos das duas expressões compartilham.
amalloy 10/01
22

Você está confundindo o compilador com esta linha:

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

O compilador vê que o resultado da expressão (à esquerda do arremesso) é a superclasse comum entre Except1 e Except2, que é Exception, e, portanto, o tipo efetivo que você está lançando se torna Exception. Não é possível pegar a instrução catch que você está tentando lançar Excep1 ou Except2.

GideonleGrange
fonte
4

Java restringe você a capturar ou declarar todos os tipos de exceção que o método pode lançar,

Ele procura por pai comum para ambas as exceções (/ todas) e espera que você capture ou declare como arremessos, por exemplo, se Excep1estenderThrowable você também precisará capturar Throwable

No primeiro caso, Java tem certeza de que está jogando Excep1ouExcep2

user7294900
fonte