Relendo exceções em Java sem perder o rastreamento de pilha


417

Em C #, posso usar a throw;instrução para repetir uma exceção, preservando o rastreamento de pilha:

try
{
   ...
}
catch (Exception e)
{
   if (e is FooException)
     throw;
}

Existe algo parecido com isto em Java ( que não perde o rastreamento de pilha original )?


4
Por que você acha que perde o stacktrace original? A única maneira de perdê-lo quando você lança a SomeOtherException nova e esquece de atribuir a causa raiz no construtor ou em initCause ().
Akarnokd 08/07/2009

4
Acredito que é assim que o código se comporta no .Net, mas não sou mais positivo. Pode valer a pena procurar em algum lugar ou executar um pequeno teste.
Ripper234

11
Throwables não são modificados jogando-os. Para atualizar o rastreamento de pilha, é necessário chamar fillInStackTrace(). Convenientemente, esse método é chamado no construtor de a Throwable.
Robert

50
Em C #, sim, throw e;perderá o rastreamento de pilha. Mas não em Java.
Tim Goodman

Respostas:


560
catch (WhateverException e) {
    throw e;
}

simplesmente retrocederá a exceção que você capturou (obviamente, o método circundante deve permitir isso por meio de sua assinatura etc.). A exceção manterá o rastreamento de pilha original.


4
Olá, InterruptedException e fornece uma mensagem de exceção não tratada quando adiciono a linha throw e. Não é assim se eu o substituir pela exceção mais ampla e. Como isso deve ser feito corretamente?
James P.

1
@ James, acabei de observar que a mensagem desaparece se adicionar "lança XxxException" na declaração da função.
shiouming 13/10/12

2
No Java 7, o compilador para esse relançamento é mais inteligente. Agora ele funciona bem com exceções específicas "throws" no método contendo.
Waldemar Wosiński

193
@ James Se você não for tratado catch(Exception e) { throw e; }. Se você catch(InterruptedException ie) { throw ie; }será tratado. Como regra geral, não catch(Exception e)- isso não é pokemon, e não queremos pegá-los todos!
corsiKa

3
@corsiKa Não é necessariamente verdade que você não deseja "pegar todos", é apenas um caso de uso diferente. Se você tiver um loop de nível superior ou manipulador de eventos (por exemplo, dentro da execução de um encadeamento) se não capturar pelo menos RuntimeException e registrá-lo, muitas vezes perderá a exceção completamente e interromperá silenciosamente um loop importante para o que geralmente é uma falha única. Também é muito bom para a funcionalidade de plug-in, onde você não sabe o que código adicional pode fazer ou lançar ... Para usos de cima para baixo como esses, a exceção de captura geralmente não é apenas uma boa idéia, mas uma prática recomendada.
Bill K

82

Eu preferiria:

try
{
    ...
}
catch (FooException fe){
   throw fe;
}
catch (Exception e)
{
    // Note: don't catch all exceptions like this unless you know what you
    // are doing.
    ...
}

6
Definitivamente adequado em Java para capturar exceções específicas do que genéricas e verificar, por exemplo,. +1
amischiefr

8
-1 porque você nunca deve capturar "Exceção" simples, a menos que saiba o que está fazendo.
Stroboskop 29/07/2009

19
@ Stroboskop: true, mas para responder, é melhor usar o mesmo código (semelhante) da pergunta!
User85421

14
Às vezes, pegar todas as exceções é ok. Como quando você está escrevendo um caso de teste. Ou para fins de registro. Ou, principalmente, onde não pegar significa bater.
precisa

1
@JohnHenckel e outros: pontos válidos inded. Atualizei a pergunta para deixar claro que a captura Exceptiongeralmente não é a coisa certa a ser feita, na maioria (mas não em todos) os casos.
Per Lundberg

74

Você também pode agrupar a exceção em outra E manter o rastreamento da pilha original passando a exceção como Throwable como o parâmetro de causa:

try
{
   ...
}
catch (Exception e)
{
     throw new YourOwnException(e);
}

8
Eu também aconselharia em adicionar uma mensagem ao lado, usando #throw new YourOwnException("Error while trying to ....", e);
Julien

isto é o que eu estava procurando, especialmente a versão do primeiro comentário, onde pode passar sua própria mensagem
Csaba

Isso mostra a mensagem de erro corretamente, mas o rastreamento de pilha mostra a linha de erro como linha com 'lançar novo ....... (e)' e não a linha original que causou a exceção.
Ashburn RK

22

Em Java é quase o mesmo:

try
{
   ...
}
catch (Exception e)
{
   if (e instanceof FooException)
     throw e;
}

5
Não, desde que você não instancie um novo objeto de exceção, o rastreamento de pilha permanece o mesmo.
Mnementh

28
Gostaria de acrescentar uma captura específico para FooException
dfa

3
Nesse caso específico, eu concordo, mas adicionar uma captura específica pode não ser a escolha certa - imagine que você tenha algum código comum para todas as exceções e depois, para uma exceção específica, repita-o novamente.
alves

1
@ MarkusLausberg Mas finalmente não pega exceções.
Robert

Sim, mas essa não era a questão.
Markus Lausberg

14

Em Java, você apenas lança a exceção capturada, throw ee não apenas throw. Java mantém o rastreamento de pilha.


6

algo assim

try 
{
  ...
}
catch (FooException e) 
{
  throw e;
}
catch (Exception e)
{
  ...
}

5
public int read(byte[] a) throws IOException {
    try {
        return in.read(a);
    } catch (final Throwable t) {
        /* can do something here, like  in=null;  */
        throw t;
    }
}

Este é um exemplo concreto em que o método lança um IOException. Os finalmeios tpodem conter apenas uma exceção lançada do bloco try. Material de leitura adicional pode ser encontrado aqui e aqui .



3

O rastreamento de pilha é preservado se você agrupar a exceção capturada em uma outra exceção (para fornecer mais informações) ou se você apenas reproduzir novamente a exceção capturada.

try{ ... }catch (FooException e){ throw new BarException("Some usefull info", e); }


2

Eu estava apenas tendo uma situação semelhante na qual meu código potencialmente gera uma série de exceções diferentes que eu só queria relançar. A solução descrita acima não estava funcionando para mim, porque o Eclipse me disse que isso throw e;leva a uma exceção sem tratamento, então fiz isso:

try
{
...
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {                    
    throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage() + "\n" + e.getStackTrace().toString());
}

Trabalhou para mim .... :)

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.