Múltiplos blocos catch e multi-catch em Java
Capture diferentes tipos de exceção em Java com múltiplos blocos catch ou uma cláusula multi-catch (Tipo1 | Tipo2 e).
Um único try pode ser seguido por qualquer número de blocos catch. Cada um declara um tipo de exceção diferente e é executado somente se o lançamento corresponder. É assim que o Java permite que um bloco de código reaja de forma diferente dependendo do que deu errado — uma falha de rede não é um erro de análise, e você pode querer tratá-los de maneiras completamente diferentes.
Múltiplos catches sequenciais
try {
String body = httpClient.get(url);
Config cfg = parser.parse(body);
apply(cfg);
} catch (IOException e) {
retryLater(url);
} catch (ParseException e) {
report("config file is malformed: " + e.getMessage());
} catch (SecurityException e) {
report("not allowed to apply config");
}Apenas um catch é executado por lançamento — o primeiro cujo tipo é uma correspondência instanceof para a exceção lançada. Após sua execução, o controle pula para a instrução após toda a instrução try, não para o próximo catch.
A ordem importa: do específico ao geral
Um catch (T e) corresponde a qualquer coisa que seja T ou qualquer subclasse de T. Se você listar uma superclasse antes de sua subclasse, o catch da subclasse fica inacessível e o compilador recusa:
try { ... }
catch (Exception e) { ... } // matches everything below Exception
catch (IOException e) { ... } // ERROR: unreachableA ordem a seguir é tipo mais específico no topo, mais amplo na base:
try { ... }
catch (FileNotFoundException e) { ... } // most specific
catch (IOException e) { ... } // wider
catch (Exception e) { ... } // catch-all (used sparingly)Isso também é um exercício útil de design: escrever os catches força você a pensar sobre quais falhas o bloco pode realmente produzir.
Multi-catch (um bloco, vários tipos)
O Java 7 adicionou a forma multi-catch: um único bloco que trata vários tipos de exceção não relacionados, separados por |:
try {
return parser.read(file);
} catch (IOException | ParseException e) {
log.warn("could not load config: " + e);
return Config.defaults();
}Use isso quando o tratamento for idêntico para várias falhas distintas. É mais curto do que dois blocos catch quase duplicados e torna óbvia a relação "estes compartilham uma resposta" à primeira vista.
Regras para saber:
- Os tipos na união não devem ser relacionados por herança.
IOException | FileNotFoundExceptionnão compila — um é subtipo do outro, então o mais amplo já o cobre. - Dentro do bloco,
eé tipado como o supertipo comum dos tipos listados. Você pode chamar métodos declarados nesse supertipo, mas não os específicos do subtipo. Para a maioria dos usos (log, encapsulamento),getMessage()etoString()são suficientes. - O parâmetro catch em um multi-catch é implicitamente final — você não pode reatribuí-lo. (Catches de tipo único são apenas efetivamente finais; a diferença não importa na prática.)
Quando dividir um try
Um erro comum de legibilidade é envolver um método inteiro em um único try gigante e depois capturar tudo que qualquer linha pode lançar. A lógica de tratamento no final fica confusa sobre qual linha falhou.
Duas formas mais limpas quando isso acontece:
- Duas instruções try separadas, cada uma com escopo para um conjunto relacionado de operações.
- Um try dentro de um método que chama métodos menores, cada um responsável por um tipo de falha.
Quanto menor o try, mais fácil é raciocinar sobre os catches. "Qual linha poderia lançar isto?" deve sempre ter uma resposta curta.
Um exemplo trabalhado
Um pequeno programa que faz três coisas — analisar um número, pesquisá-lo em um array, dividir por ele — cada uma das quais pode falhar à sua própria maneira. Capturamos cada falha com um handler dedicado para que as mensagens permaneçam específicas. O último catch usa a forma multi-catch para agrupar duas falhas que compartilham uma resposta.
Cada entrada percorre um caminho diferente pelos catches, mas cada iteração imprime uma linha limpa — o programa nunca decepciona o usuário.
O que vem a seguir
try/catch trata o caminho feliz e o caminho de falha. A terceira cláusula, finally, trata as coisas que precisam acontecer de qualquer forma. Continue para bloco finally em Java.