Posso capturar várias exceções de Java na mesma cláusula de captura?


699

Em Java, eu quero fazer algo assim:

try {
    ...     
} catch (/* code to catch IllegalArgumentException, SecurityException, 
            IllegalAccessException, and NoSuchFieldException at the same time */) {
   someCode();
}

...ao invés de:

try {
    ...     
} catch (IllegalArgumentException e) {
    someCode();
} catch (SecurityException e) {
    someCode();
} catch (IllegalAccessException e) {
    someCode();
} catch (NoSuchFieldException e) {
    someCode();
}

Há alguma maneira de fazer isso?

Respostas:


1131

Isso é possível desde o Java 7 . A sintaxe para um bloco de captura múltipla é:

try { 
  ...
} catch (IOException | SQLException ex) { 
  ...
}

Lembre-se, porém, de que se todas as exceções pertencerem à mesma hierarquia de classes, você poderá simplesmente capturar esse tipo de exceção base.

Observe também que você não pode capturar ExceptionA e ExceptionB no mesmo bloco se ExceptionB for herdado, direta ou indiretamente, de ExceptionA. O compilador irá reclamar:

Alternatives in a multi-catch statement cannot be related by subclassing
  Alternative ExceptionB is a subclass of alternative ExceptionA

81
TT - por que redefinir o operador bitwise or( |)? Por que não usar uma vírgula, ou o operador que tem um significado mais semelhante, o logical or( ||)?
ArtOfWarfare 6/11

11
@ArtOfWarfare Talvez eles pensassem que isso não importaria mais depois que eles já tivessem criado a sintaxe para vários limites para genéricos.
22416 JimmyB

12
O sinal XOR (I) não é o mesmo que OR (||), A | B significa A ou B, mas não ambos A || B significa A ou B ou ambos; para exceções, é exceçãoA ou exceçãoB, mas não as duas ao mesmo tempo. é por isso que eles usaram XOR cantar em vez de OR e você pode ver isso claramente quando a exceção é joga se você colocar 2 exceções um deles é sub tipo de outra
user1512999

41
@ user1512999 em Java, o XOR bit a bit é ^ (circunflexo) e o OR bit a bit é | (pipe) docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
Lewis Baumstark

6
Vale a pena mencionar que o tipo de uma excepção travado no bloco multi-captura é V. dahliae ao progenitor comum mais derivado
yanpas

104

Não exatamente antes do Java 7, mas eu faria algo assim:

Java 6 e anterior

try {
  //.....
} catch (Exception exc) {
  if (exc instanceof IllegalArgumentException || exc instanceof SecurityException || 
     exc instanceof IllegalAccessException || exc instanceof NoSuchFieldException ) {

     someCode();

  } else if (exc instanceof RuntimeException) {
     throw (RuntimeException) exc;     

  } else {
    throw new RuntimeException(exc);
  }

}



Java 7

try {
  //.....
} catch ( IllegalArgumentException | SecurityException |
         IllegalAccessException |NoSuchFieldException exc) {
  someCode();
}

11
Observe que seu exemplo do Java 6 interrompe a capacidade do compilador de dizer o que será lançado de onde.
22613 MichaelBlume

2
@ MichaelBlume True, o que não é tão ruim. Você sempre pode obter a exceção original com exc.getCause(). Como uma observação lateral, Robert C. Martin (entre outros) recomenda o uso de exceções não verificadas (o compilador não tem idéia de que tipo de exceção será lançada a partir daí); consulte o Capítulo 7: Tratamento de erros em seu livro Código limpo .
user454322

4
No seu exemplo do Java 6, você não deveria repetir a exceção original em vez de criar uma nova instância de exceção, ou seja, em throw excvez de throw new RuntimeException(exc)?
David DeMar

5
Essa é uma prática muito ruim, do ponto de vista da legibilidade.
Rajesh J Advani

3
Caso a operação seja um pouco cara, é melhor evitar o máximo possível.
Paramesh Korrakuti

23

No Java 7, você pode definir várias cláusulas de captura, como:

catch (IllegalArgumentException | SecurityException e)
{
    ...
}

16

Se houver uma hierarquia de exceções, você poderá usar a classe base para capturar todas as subclasses de exceções. No caso degenerado, você pode capturar todas as exceções de Java com:

try {
   ...
} catch (Exception e) {
   someCode();
}

Em um caso mais comum, se RepositoryException for a classe base e PathNotFoundException for uma classe derivada, então:

try {
   ...
} catch (RepositoryException re) {
   someCode();
} catch (Exception e) {
   someCode();
}

O código acima capturará RepositoryException e PathNotFoundException para um tipo de tratamento de exceção e todas as outras exceções são agrupadas. Desde o Java 7, conforme a resposta de @ OscarRyz acima:

try { 
  ...
} catch( IOException | SQLException ex ) { 
  ...
}

7
As cláusulas de captura BTW são tratadas em ordem; portanto, se você colocar uma classe de exceção pai antes de uma classe filho, nunca será chamada, por exemplo: try {...} catch (Exception e) {someCode (); } catch (RepositoryException re) {// nunca alcançado}
Michael Shopsin

4
Na verdade, precisamente porque nunca pode ser alcançado, esse código nem compila.
polygenelubricants

15

Não, um por cliente.

Você pode capturar uma superclasse, como java.lang.Exception, desde que execute a mesma ação em todos os casos.

try {
    // some code
} catch(Exception e) { //All exceptions are caught here as all are inheriting java.lang.Exception
    e.printStackTrace();
}

Mas essa pode não ser a melhor prática. Você só deve capturar uma exceção quando tiver uma estratégia para lidar com isso de verdade - e o registro e a repetição não estão "lidando com isso". Se você não tiver uma ação corretiva, é melhor adicioná-la à assinatura do método e deixar que ela borbulhe para alguém que possa lidar com a situação.


20
Posso solicitar que você reformule a parte sobre a captura de java.lang.Exception? Percebo que é um exemplo, mas sinto que algumas pessoas podem ler esta resposta e dizer: "Ah, tudo bem, vou pegar a exceção então", quando provavelmente não é isso que elas querem (ou deveriam) fazer.
Rob Hruska

2
Eu sabia sobre isso, mas eu não quero fazê-lo ... Oh, bem, acho que estou preso com 4 capturas em seguida, até a próxima versão do Java ...
froadie

@duffymo: O que há de errado com o registro e a repetição? Exceto que ele desorganiza o código, é equivalente a não capturá-lo, não é? Visto da perspectiva geral da estratégia de tratamento de erros. O que é ruim é fazer logon e não repetir.
precisa

5
Não considero o registro e a nova tentativa de manipular nada. Eu preferiria deixar isso acontecer para alguém que possa fazer algo significativo. A última camada em que as exceções nunca devem escapar (por exemplo, controladores em um aplicativo da web) deve ser a única a registrar o erro nesse caso.
duffymo

Eu sou o único que acha absurdo que um log não seja gerado automaticamente para mim? Parece que todos nós temos que escrever a mesma mensagem estúpida de log toda vez que algum código pode gerar uma exceção.
ArtOfWarfare 6/11/2013

10

Uma alternativa mais limpa (mas menos detalhada e talvez não a preferida) à resposta do usuário454322 no Java 6 (ou seja, Android) seria pegar todos os se Exceptionvoltar a jogar RuntimeException. Isso não funcionaria se você estiver planejando capturar outros tipos de exceções além da pilha (a menos que você também as jogue novamente), mas efetivamente capturará todas as exceções verificadas .

Por exemplo:

try {
    // CODE THAT THROWS EXCEPTION
} catch (Exception e) {
    if (e instanceof RuntimeException) {
        // this exception was not expected, so re-throw it
        throw e;
    } else {
        // YOUR CODE FOR ALL CHECKED EXCEPTIONS
    } 
}

Dito isto, para maior detalhamento, pode ser melhor definir uma variável booleana ou outra variável e, com base nisso, executar algum código após o bloco try-catch.


1
Essa abordagem evita que o compilador determine se um "bloco de captura" será ou não acessível.
the_new_mr

3

No pré-7, que tal:

  Boolean   caught = true;
  Exception e;
  try {
     ...
     caught = false;
  } catch (TransformerException te) {
     e = te;
  } catch (SocketException se) {
     e = se;
  } catch (IOException ie) {
     e = ie;
  }
  if (caught) {
     someCode(); // You can reference Exception e here.
  }

3
Seria uma boa solução. Que tal inserir o controle final de caughtem um finallybloco?
Andrea_86 23/03

Isso requer mais linhas do que a pergunta original.
Leandro Glossman

1

Sim. Aqui está o caminho usando o separador pipe (|),

try
{
    .......
}    
catch
{
    catch(IllegalArgumentException | SecurityException | IllegalAccessException | NoSuchFieldException e)
}

Qual é esse estilo de código? O bloco catch em um bloco try?
Sam

1

Para o kotlin, não é possível por enquanto, mas eles consideraram adicioná-lo: Source
Mas, por enquanto, apenas um pequeno truque:

try {
    // code
} catch(ex:Exception) {
    when(ex) {
        is SomeException,
        is AnotherException -> {
            // handle
        }
        else -> throw ex
    }
}

0

Capture a exceção que é uma classe pai na hierarquia de exceções. Naturalmente, isso é uma má prática . No seu caso, a exceção pai comum passa a ser a classe Exception, e capturar qualquer exceção que seja uma instância de Exception é realmente uma prática ruim - exceções como NullPointerException geralmente são erros de programação e geralmente devem ser resolvidas verificando-se valores nulos.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.