Por que é throw e
permitido, mas não throw a
, no seguinte caso?
void test() {
try {
System.out.println();
} catch (Error | RuntimeException e) {
var a = e;
//throw a; unreported exception Throwable; must be caught or declared to be thrown
throw e;
}
}
Tudo isso intuitivamente faz sentido, mas a partir do JLS 14.20
Uma cláusula multi-catch pode ser considerada uma sequência de cláusulas uni-catch. Ou seja, uma cláusula catch onde o tipo do parâmetro de exceção é denotado como uma união
D1|D2|...|Dn
é equivalente a uma sequência de n cláusulas catch onde os tipos dos parâmetros de exceção são tipos de classeD1, D2, ..., Dn
respectivamente. No bloco de cada uma das n cláusulas catch, o tipo declarado do parâmetro de exceção élub(D1, D2, ..., Dn)
.
Como lub(Error,RuntimeException)
is Throwable
, o código acima deve ser equivalente a:
try {
System.out.println();
} catch (Error e) {
Throwable lub = e;
throw lub;
} catch (RuntimeException e) {
Throwable lub = e;
throw lub;
}
(que obviamente não compila)
Além disso, o tipo de a
é o tipo de e
"quando tratado como se não aparecesse em um contexto de atribuição" ( JLS 14.4.1 ), mas como mostrado acima não é o mesmo que o tipo de e
.
Há algo que eu esqueci?
Editar : esta não é uma duplicata de Por que é legal lançar novamente um Throwable em certos casos, sem declará-lo? porque esta questão é específica para multi-catch (que não é discutida lá) e surge devido a um mal-entendido de um fragmento específico do JLS que aborda multi-catch. As respostas fornecidas nesta pergunta me ajudaram a ligar os pontos :)