No entanto, às vezes você precisa detectar erros específicos.
Se você estiver escrevendo um código de estrutura (carregando classes de terceiros), pode ser sensato capturar LinkageError(nenhuma definição de classe encontrada, link não satisfeito, mudança de classe incompatível).
Eu também vi alguns códigos estúpidos de terceiros lançando subclasses de Error, então você terá que lidar com eles também.
A propósito, não tenho certeza de que não seja possível recuperar OutOfMemoryError.
Isso eu tive que fazer exatamente para carregar as DLLs, que falharia se não fossem configuradas corretamente. Não é um erro fatal no caso desta aplicação.
Mario Ortegón
7
Às vezes, faz sentido capturar OutOfMemoryError - por exemplo, quando você está criando listas de grandes matrizes.
SpaceTrucker
3
@SpaceTrucker: essa abordagem funciona bem em aplicativos multithread ou há um risco significativo de que alocações menores em outros threads falhem por causa disso? … Presumivelmente apenas se seus arrays fossem pequenos o suficiente para serem alocados, mas não deixassem nada para mais ninguém.
PJTraill
@PJTraill Não tenho certeza sobre isso. Isso exigiria algumas amostras estatísticas do mundo real. Pensei ter visto esse código, mas não me lembro onde estava.
SpaceTrucker de
51
Nunca. Você nunca pode ter certeza de que o aplicativo será capaz de executar a próxima linha de código. Se você receber um OutOfMemoryError, não terá garantia de que poderá fazer nada de maneira confiável . Captura RuntimeException e exceções verificadas, mas nunca erros.
Nunca diga nunca. temos código de teste que faz uma "declaração falsa;" em seguida, captura o AssertionError para garantir que o sinalizador -ea esteja definido. Fora isso ... sim, provavelmente nunca ;-)
Programador Outlaw
3
Que tal um aplicativo de servidor que entrega solicitações para threads de trabalho. Não faria sentido capturar Throwable no thread de trabalho para detectar quaisquer erros e, pelo menos, tentar registrar o que deu errado?
Leigh
11
Nunca ... exceto quando for absolutamente necessário. Nunca é uma palavra forte e sempre há exceções às regras. Se você estiver construindo uma estrutura, não é improvável que tenha que detectar e lidar com certos erros, mesmo que seja apenas para registrar.
Robin
E os erros, por exemplo, NoSuchMethodError provenientes de métodos de biblioteca de terceiros?
ha9u63ar
@OutlawProgrammer Apenas para registro, existem outras maneiras de fazer o mesmo teste:boolean assertionsEnabled = false; assert assertionsEnabled = true;
shmosel
16
Geralmente, você deve sempre capturar java.lang.Errore gravar em um log ou exibi-lo para o usuário. Eu trabalho com suporte e vejo diariamente que os programadores não conseguem contar o que aconteceu em um programa.
Se você tiver um encadeamento daemon, deverá evitar que ele seja encerrado. Em outros casos, seu aplicativo funcionará corretamente.
Você só deve pegar java.lang.Error no nível mais alto.
Se você olhar a lista de erros, verá que a maioria pode ser tratada. Por exemplo umZipError ocorre na leitura de arquivos zip corrompidos.
Os erros mais comuns são OutOfMemoryError e NoClassDefFoundError, que na maioria dos casos são problemas de tempo de execução.
Por exemplo:
int length =Integer.parseInt(xyz);byte[] buffer =newbyte[length];
pode produzir um, OutOfMemoryErrormas é um problema de tempo de execução e não há razão para encerrar seu programa.
NoClassDefFoundErrorocorrem principalmente se uma biblioteca não estiver presente ou se você trabalhar com outra versão do Java. Se for uma parte opcional de seu programa, você não deve encerrá-lo.
Posso dar muitos outros exemplos de por que é uma boa ideia pegar Throwableno nível superior e produzir uma mensagem de erro útil.
Eu suspeito que é melhor nesses casos falhar o daemon com alertas adequados do que ter a possibilidade de ele permanecer vivo como algum fantasma etéreo em um jvm com falha, onde pode dar o falso pretexto de que está realmente vivo e fazendo algo
Andrew Norman
OutOfMemoryErrornão é um erro de tempo de execução, não há garantia de que o aplicativo possa se recuperar dele. Se você tiver sorte, poderá obter OOM, new byte[largeNumber]mas se essa alocação não for suficiente para causar OOM, pode ser disparado na próxima linha ou no próximo encadeamento. Este é um problema de tempo de execução porque se lengthfor uma entrada não confiável, ela deve ser validada antes da chamada new byte[].
Jeeyoung Kim
NoClassDefFoundErrorpode ocorrer em qualquer lugar , pois é invocado quando o código Java compilado não consegue encontrar uma classe. Se o seu JDK estiver configurado incorretamente, ele pode desencadear a tentativa de usar a java.util.*classe e é praticamente impossível programar contra ela. Se você está opcionalmente incluindo uma dependência, você deve usar ClassLoaderpara verificar se ela existe, o que gera ClassNotFoundException.
Jeeyoung Kim
1
ZipErrorindica que o arquivo jar contendo classes é um arquivo zip corrompido. Este é um problema muito sério e neste ponto você não pode confiar em nenhum código que seja executado e seria uma coisa irresponsável tentar "se recuperar" dele.
Jeeyoung Kim
2
Em geral, pode ser útil capturar java.lang.Errorou java.lang.Throwableno nível superior e tentar fazer algo com ele - digamos, registrar uma mensagem de erro. Mas nesse ponto não há garantia de que isso será executado. Se sua JVM estiver OOM, tentar registrar pode alocar mais Strings, o que aciona outro OOM.
Jeeyoung Kim
15
Em um ambiente multithread, você geralmente deseja capturá-lo! Quando você pegá-lo, registre-o e encerre o aplicativo inteiro! Se você não fizer isso, algum encadeamento que possa estar fazendo alguma parte crucial estará morto e o restante do aplicativo pensará que tudo está normal. Fora disso, muitas situações indesejadas podem acontecer. Um menor problema é que você não seria capaz de encontrar facilmente a raiz do problema, se outros threads começarem a lançar algumas exceções por causa de um thread não funcionar.
Mesmo em alguns casos, você desejaria lidar com erros diferentes de forma diferente, por exemplo, em OutOfMemoryError você seria capaz de fechar o aplicativo regularmente (talvez até mesmo liberar alguma memória e continuar), em outros, não há muito o que fazer.
chamar o sistema, sair ao pegar um lançável tem a consequência indesejada de matar tudo em execução na JVM e não apenas o aplicativo em questão. Normalmente não é uma boa prática para aplicativos da web que podem ser hospedados em um servidor de aplicativos com outros aplicativos da web (sem mencionar que afetaria o próprio servidor de aplicativos).
Andrew Norman
9
Muito raramente.
Eu diria que apenas no nível superior de um tópico para TENTAR emitir uma mensagem com o motivo do término de um tópico.
Se você está em uma estrutura que faz esse tipo de coisa por você, deixe isso para a estrutura.
Quase nunca. Os erros são projetados para serem problemas sobre os quais os aplicativos geralmente não podem fazer nada. A única exceção pode ser lidar com a apresentação do erro, mas mesmo isso pode não ocorrer como planejado dependendo do erro.
Um Erroré uma subclasse de Throwable
que indica problemas sérios que um aplicativo razoável não deve tentar detectar. A maioria desses erros são condições anormais. [...]
Um método não é obrigado a declarar em sua cláusula throws quaisquer subclasses de Error que possam ser lançadas durante a execução do método, mas não detectadas, uma vez que esses erros são condições anormais que nunca deveriam ocorrer.
Como a especificação menciona, um Erroré lançado apenas em circunstâncias que são. Provavelmente, quando Errorocorre, há muito pouco que o aplicativo pode fazer e, em algumas circunstâncias, a própria máquina virtual Java pode estar em um estado instável (como VirtualMachineError)
Embora an Errorseja uma subclasse do Throwableque significa que pode ser capturado por uma try-catchcláusula, provavelmente não é realmente necessário, pois o aplicativo estará em um estado anormal quando um Errorfor lançado pela JVM.
Se você for louco o suficiente para criar uma nova estrutura de teste de unidade, seu executor de teste provavelmente precisará capturar java.lang.AssertionError lançado por quaisquer casos de teste.
E há alguns outros casos em que, se você detectar um erro, terá que relançá-lo . Por exemplo, ThreadDeath nunca deve ser capturado, pode causar um grande problema se você capturá-lo em um ambiente fechado (por exemplo, um servidor de aplicativos):
Um aplicativo deve capturar instâncias dessa classe apenas se precisar limpar depois de ser encerrado de forma assíncrona. Se ThreadDeath for capturado por um método, é importante que ele seja relançado para que o thread realmente morra.
O que na verdade não é um problema, porque você simplesmente não detecta Errors.
Bombe
4
Muito, muito raramente.
Eu fiz isso apenas para um caso conhecido muito específico. Por exemplo, java.lang.UnsatisfiedLinkError poderia ser lançado se dois ClassLoader independentes carregassem a mesma DLL. (Concordo que devo mover o JAR para um carregador de classe compartilhado)
Mas o caso mais comum é que você precisava fazer login para saber o que aconteceu quando o usuário veio reclamar. Você quer uma mensagem ou um pop-up para o usuário, em vez de silenciosamente morto.
Mesmo programadores em C / C ++, eles apresentam um erro e dizem algo que as pessoas não entendem antes de sair (por exemplo, falha de memória).
Em um aplicativo Android, estou capturando um java.lang.VerifyError . Uma biblioteca que estou usando não funciona em dispositivos com uma versão antiga do sistema operacional e o código da biblioteca gerará esse erro. Eu poderia evitar o erro, é claro, verificando a versão do sistema operacional em tempo de execução, mas:
O SDK mais antigo compatível pode mudar no futuro para a biblioteca específica
O bloco de erro try-catch faz parte de um mecanismo maior de fallback. Alguns dispositivos específicos, embora devam oferecer suporte à biblioteca, lançam exceções. Eu pego VerifyError e todas as exceções para usar uma solução de fallback.
adicionando o valor de um conjunto de testes não abortando
Jono
2
Idealmente, não devemos tratar / detectar erros. Mas pode haver casos em que precisamos fazer, com base no requisito de estrutura ou aplicação. Digamos que eu tenha um daemon de XML Parser que implementa DOM Parser que consome mais memória. Se houver um requisito como o thread do analisador, não deve ser encerrado quando ele obtém OutOfMemoryError , em vez disso, ele deve tratá-lo e enviar uma mensagem / e-mail ao administrador do aplicativo / estrutura.
idealmente, nunca devemos detectar Erro em nosso aplicativo Java, pois é uma condição anormal. A aplicação estaria em estado anormal e poderia resultar em engatilhamento ou dando algum resultado seriamente errado.
Pode ser apropriado detectar o erro nos testes de unidade que verificam se uma asserção foi feita. Se alguém desabilitar afirmações ou de outra forma excluir a afirmação que você gostaria de saber
Ocorre um Erro quando a JVM não está mais funcionando conforme o esperado ou está prestes a. Se você detectar um erro, não há garantia de que o bloco catch será executado, e muito menos que será executado até o fim.
Dependerá também do computador em execução, do estado atual da memória, portanto não há como testar, tentar e fazer o melhor. Você terá apenas um resultado complicado.
Você também diminuirá a legibilidade do seu código.
Respostas:
Geralmente, nunca.
No entanto, às vezes você precisa detectar erros específicos.
Se você estiver escrevendo um código de estrutura (carregando classes de terceiros), pode ser sensato capturar
LinkageError
(nenhuma definição de classe encontrada, link não satisfeito, mudança de classe incompatível).Eu também vi alguns códigos estúpidos de terceiros lançando subclasses de
Error
, então você terá que lidar com eles também.A propósito, não tenho certeza de que não seja possível recuperar
OutOfMemoryError
.fonte
Nunca. Você nunca pode ter certeza de que o aplicativo será capaz de executar a próxima linha de código. Se você receber um
OutOfMemoryError
, não terá garantia de que poderá fazer nada de maneira confiável . Captura RuntimeException e exceções verificadas, mas nunca erros.http://pmd.sourceforge.net/rules/strictexception.html
fonte
boolean assertionsEnabled = false; assert assertionsEnabled = true;
Geralmente, você deve sempre capturar
java.lang.Error
e gravar em um log ou exibi-lo para o usuário. Eu trabalho com suporte e vejo diariamente que os programadores não conseguem contar o que aconteceu em um programa.Se você tiver um encadeamento daemon, deverá evitar que ele seja encerrado. Em outros casos, seu aplicativo funcionará corretamente.
Você só deve pegar
java.lang.Error
no nível mais alto.Se você olhar a lista de erros, verá que a maioria pode ser tratada. Por exemplo um
ZipError
ocorre na leitura de arquivos zip corrompidos.Os erros mais comuns são
OutOfMemoryError
eNoClassDefFoundError
, que na maioria dos casos são problemas de tempo de execução.Por exemplo:
pode produzir um,
OutOfMemoryError
mas é um problema de tempo de execução e não há razão para encerrar seu programa.NoClassDefFoundError
ocorrem principalmente se uma biblioteca não estiver presente ou se você trabalhar com outra versão do Java. Se for uma parte opcional de seu programa, você não deve encerrá-lo.Posso dar muitos outros exemplos de por que é uma boa ideia pegar
Throwable
no nível superior e produzir uma mensagem de erro útil.fonte
OutOfMemoryError
não é um erro de tempo de execução, não há garantia de que o aplicativo possa se recuperar dele. Se você tiver sorte, poderá obter OOM,new byte[largeNumber]
mas se essa alocação não for suficiente para causar OOM, pode ser disparado na próxima linha ou no próximo encadeamento. Este é um problema de tempo de execução porque selength
for uma entrada não confiável, ela deve ser validada antes da chamadanew byte[]
.NoClassDefFoundError
pode ocorrer em qualquer lugar , pois é invocado quando o código Java compilado não consegue encontrar uma classe. Se o seu JDK estiver configurado incorretamente, ele pode desencadear a tentativa de usar ajava.util.*
classe e é praticamente impossível programar contra ela. Se você está opcionalmente incluindo uma dependência, você deve usarClassLoader
para verificar se ela existe, o que geraClassNotFoundException
.ZipError
indica que o arquivo jar contendo classes é um arquivo zip corrompido. Este é um problema muito sério e neste ponto você não pode confiar em nenhum código que seja executado e seria uma coisa irresponsável tentar "se recuperar" dele.java.lang.Error
oujava.lang.Throwable
no nível superior e tentar fazer algo com ele - digamos, registrar uma mensagem de erro. Mas nesse ponto não há garantia de que isso será executado. Se sua JVM estiver OOM, tentar registrar pode alocar maisString
s, o que aciona outro OOM.Em um ambiente multithread, você geralmente deseja capturá-lo! Quando você pegá-lo, registre-o e encerre o aplicativo inteiro! Se você não fizer isso, algum encadeamento que possa estar fazendo alguma parte crucial estará morto e o restante do aplicativo pensará que tudo está normal. Fora disso, muitas situações indesejadas podem acontecer. Um menor problema é que você não seria capaz de encontrar facilmente a raiz do problema, se outros threads começarem a lançar algumas exceções por causa de um thread não funcionar.
Por exemplo, geralmente o loop deve ser:
Mesmo em alguns casos, você desejaria lidar com erros diferentes de forma diferente, por exemplo, em OutOfMemoryError você seria capaz de fechar o aplicativo regularmente (talvez até mesmo liberar alguma memória e continuar), em outros, não há muito o que fazer.
fonte
OutOfMemoryError
e continuar ao invés de existir prontamente não é aconselhável porque seu programa está em um estado indefinido .Muito raramente.
Eu diria que apenas no nível superior de um tópico para TENTAR emitir uma mensagem com o motivo do término de um tópico.
Se você está em uma estrutura que faz esse tipo de coisa por você, deixe isso para a estrutura.
fonte
Quase nunca. Os erros são projetados para serem problemas sobre os quais os aplicativos geralmente não podem fazer nada. A única exceção pode ser lidar com a apresentação do erro, mas mesmo isso pode não ocorrer como planejado dependendo do erro.
fonte
Um
Error
geralmente não deve ser detectado , pois indica uma condição anormal que nunca deve ocorrer .Na especificação da API Java para a
Error
classe:Como a especificação menciona, um
Error
é lançado apenas em circunstâncias que são. Provavelmente, quandoError
ocorre, há muito pouco que o aplicativo pode fazer e, em algumas circunstâncias, a própria máquina virtual Java pode estar em um estado instável (comoVirtualMachineError
)Embora an
Error
seja uma subclasse doThrowable
que significa que pode ser capturado por umatry-catch
cláusula, provavelmente não é realmente necessário, pois o aplicativo estará em um estado anormal quando umError
for lançado pela JVM.Há também uma seção curta sobre este tópico na Seção 11.5 A hierarquia de exceções da especificação da linguagem Java, 2ª edição .
fonte
Se você for louco o suficiente para criar uma nova estrutura de teste de unidade, seu executor de teste provavelmente precisará capturar java.lang.AssertionError lançado por quaisquer casos de teste.
Caso contrário, veja outras respostas.
fonte
E há alguns outros casos em que, se você detectar um erro, terá que relançá-lo . Por exemplo, ThreadDeath nunca deve ser capturado, pode causar um grande problema se você capturá-lo em um ambiente fechado (por exemplo, um servidor de aplicativos):
fonte
Error
s.Muito, muito raramente.
Eu fiz isso apenas para um caso conhecido muito específico. Por exemplo, java.lang.UnsatisfiedLinkError poderia ser lançado se dois ClassLoader independentes carregassem a mesma DLL. (Concordo que devo mover o JAR para um carregador de classe compartilhado)
Mas o caso mais comum é que você precisava fazer login para saber o que aconteceu quando o usuário veio reclamar. Você quer uma mensagem ou um pop-up para o usuário, em vez de silenciosamente morto.
Mesmo programadores em C / C ++, eles apresentam um erro e dizem algo que as pessoas não entendem antes de sair (por exemplo, falha de memória).
fonte
Em um aplicativo Android, estou capturando um java.lang.VerifyError . Uma biblioteca que estou usando não funciona em dispositivos com uma versão antiga do sistema operacional e o código da biblioteca gerará esse erro. Eu poderia evitar o erro, é claro, verificando a versão do sistema operacional em tempo de execução, mas:
fonte
é muito útil capturar java.lang.AssertionError em um ambiente de teste ...
fonte
Idealmente, não devemos tratar / detectar erros. Mas pode haver casos em que precisamos fazer, com base no requisito de estrutura ou aplicação. Digamos que eu tenha um daemon de XML Parser que implementa DOM Parser que consome mais memória. Se houver um requisito como o thread do analisador, não deve ser encerrado quando ele obtém OutOfMemoryError , em vez disso, ele deve tratá-lo e enviar uma mensagem / e-mail ao administrador do aplicativo / estrutura.
fonte
idealmente, nunca devemos detectar Erro em nosso aplicativo Java, pois é uma condição anormal. A aplicação estaria em estado anormal e poderia resultar em engatilhamento ou dando algum resultado seriamente errado.
fonte
Pode ser apropriado detectar o erro nos testes de unidade que verificam se uma asserção foi feita. Se alguém desabilitar afirmações ou de outra forma excluir a afirmação que você gostaria de saber
fonte
Ocorre um Erro quando a JVM não está mais funcionando conforme o esperado ou está prestes a. Se você detectar um erro, não há garantia de que o bloco catch será executado, e muito menos que será executado até o fim.
Dependerá também do computador em execução, do estado atual da memória, portanto não há como testar, tentar e fazer o melhor. Você terá apenas um resultado complicado.
Você também diminuirá a legibilidade do seu código.
fonte