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 )?

ripper234
fonte
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
Alguns doc da Oracle sobre exceções com Java 7: Catching Vários tipos de exceção e Relançando Exceções com uma melhor verificação de tipo
Guillaume Husta

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.

Brian Agnew
fonte
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.
    ...
}
Markus Lausberg
fonte
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);
}
Olvagor
fonte
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;
}
alves
fonte
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.

David M
fonte
6

algo assim

try 
{
  ...
}
catch (FooException e) 
{
  throw e;
}
catch (Exception e)
{
  ...
}
cdeszaq
fonte
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 .

Daniel
fonte
1
Não precisa ser final. Consulte docs.oracle.com/javase/7/docs/technotes/guides/language/… e stackoverflow.com/a/6889301/131160
jcsahnwaldt diz GoFundMonica
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); }

Sindre
fonte
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 .... :)

Matthias
fonte