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?

froadie
fonte

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
OscarRyz
fonte
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();
}
user454322
fonte
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)
{
    ...
}
crusam
fonte
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 ) { 
  ...
}
Michael Shopsin
fonte
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.

duffymo
fonte
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.

Oleg Vaskevich
fonte
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.
  }
Contas
fonte
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)
}
Shiva
fonte
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
    }
}
Dr.jacky
fonte
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.

Vineet Reynolds
fonte