Quando capturar java.lang.Error?

Em que situações um deles deve capturar java.lang.Error em um aplicativo?

Geralmente nunca. No entanto, às vezes você precisa pegar erros específicos.

Se você está escrevendo um código framework-ish (carregando classs de terceiros), pode ser sábio pegar LinkageErrors (nenhuma class encontrada, link insatisfeito, alteração de class incompatível). Eu também vi algum código estúpido de terceiros jogando subcategorias de erros, então você terá que lidar com isso também.

A propósito, não tenho certeza se não é possível recuperar do OutOfMemory.

Nunca. Você nunca pode ter certeza de que o aplicativo é capaz de executar a próxima linha de código. Se você obtiver um OutOfMemoryError , não terá garantia de que será capaz de fazer qualquer coisa com segurança . Catch RuntimeException e Exceções marcadas, mas nunca Erros.

http://pmd.sourceforge.net/rules/strictexception.html

Geralmente você deve sempre capturar java.lang.Error e gravá-lo em um log ou exibi-lo ao usuário. Eu trabalho no suporte e vejo diariamente que os programadores não podem dizer o que aconteceu em um programa.

Se você tiver um thread do daemon, deverá impedi-lo de ser finalizado. Em outros casos, seu aplicativo funcionará corretamente.

Você só deve pegar o java.lang.Error no nível mais alto.

Se você observar a lista de erros, verá que a maioria pode ser tratada. Por exemplo, um ZipError ocorre ao ler arquivos zip corrompidos.

Os erros mais comuns são OutOfMemoryError e NoClassDefFoundError , que são, na maioria dos casos, problemas de tempo de execução.

Por exemplo:

 int length = Integer.parseInt(xyz); byte[] buffer = new byte[length]; 

pode produzir um OutOfMemoryError mas é um problema de tempo de execução e não há razão para terminar seu programa.

NoClassDefFoundError ocorre principalmente se uma biblioteca não estiver presente ou se você trabalhar com outra versão do Java. Se é uma parte opcional do seu programa, então você não deve encerrar seu programa.

Eu posso dar muitos mais exemplos de por que é uma boa idéia pegar Throwable no nível superior e produzir uma mensagem de erro útil.

No ambiente multithread, você geralmente quer pegá-lo! Quando você pegá-lo, registre-o e termine a aplicação inteira! Se você não fizer isso, algum segmento que pode estar fazendo alguma parte crucial estaria morto, e o restante do aplicativo pensará que tudo está normal. Fora disso, muitas situações indesejadas podem acontecer. Um pequeno problema é que você não conseguirá encontrar facilmente o problema, se outros threads começarem a gerar algumas exceções, porque um thread não está funcionando.

Por exemplo, geralmente o loop deve ser:

 try { while (shouldRun()) { doSomething(); } } catch (Throwable t) { log(t); stop(); System.exit(1); } 

Mesmo em alguns casos, você iria querer lidar com erros diferentes de forma diferente, por exemplo, em OutOfMemoryError você seria capaz de fechar o aplicativo regularmente (até mesmo liberar alguma memory e continuar), em outros, não há muito o que fazer.

Muito raramente.

Eu diria apenas no nível superior de um segmento, a fim de tentar emitir uma mensagem com o motivo de um thread morrer.

Se você está em uma estrutura que faz esse tipo de coisa para você, deixe-a no framework.

Quase nunca. Erros são projetados para serem problemas que 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 funcionar conforme planejado, dependendo do erro.

Um Error geralmente não deve ser detectado , pois indica uma condição anormal que nunca deve ocorrer .

Da especificação da API Java para a class Error :

Um Error é uma subclass de Throwable que indica problemas sérios que um aplicativo razoável não deve tentar capturar. A maioria desses erros são condições anormais. […]

Um método não é obrigado a declarar em sua cláusula throws quaisquer subclasss de Error que possam ser lançadas durante a execução do método, mas não capturadas, uma vez que esses erros são condições anormais que nunca devem ocorrer.

Como a especificação menciona, um Error só é lançado em circunstâncias que são Chances, quando ocorre um Error , há muito pouco que o aplicativo pode fazer e, em algumas circunstâncias, a própria Java Virtual Machine pode estar em um estado instável (como VirtualMachineError )

Embora um Error seja uma subclass de Throwable que significa que ele pode ser capturado por uma cláusula try-catch , mas provavelmente não é realmente necessário, pois o aplicativo estará em um estado anormal quando um Error for lançado pela JVM.

Há também uma pequena seção sobre este tópico na Seção 11.5 A hierarquia de exceções da especificação da linguagem Java, 2ª edição .

Se você é 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 qualquer caso de teste.

Caso contrário, veja outras respostas.

E há alguns outros casos em que, se você detectar um erro, precisará repassá-lo . Por exemplo ThreadDeath nunca deve ser pego, pode causar um grande problema é você pegá-lo em um ambiente contido (por exemplo, um servidor de aplicativos):

Um aplicativo deve capturar instâncias dessa class somente se precisar ser limpo depois de ser finalizado de forma assíncrona. Se ThreadDeath for capturado por um método, é importante que seja relançado para que a thread realmente morra.

Muito raramente.

Eu fiz isso apenas para um caso muito específico e conhecido. Por exemplo, java.lang.UnsatisfiedLinkError poderia ser lançado se dois Independent ClassLoader carregassem a mesma DLL. (Eu concordo que eu deveria mover o JAR para um classloader compartilhado)

Mas o caso mais comum é que você precisava de registro para saber o que aconteceu quando o usuário chegou para reclamar. Você quer uma mensagem ou um pop-up para o usuário, em vez de silenciosamente morto.

Mesmo programador em C / C ++, eles mostram um erro e dizem algo que as pessoas não entendem antes de sair (por exemplo, falha de memory).

Em um aplicativo Android eu estou pegando um java.lang.VerifyError . Uma biblioteca que estou usando não funcionará em dispositivos com uma versão antiga do sistema operacional e o código da biblioteca causará esse erro. Eu poderia, claro, evitar o erro, verificando a versão do sistema operacional em tempo de execução, mas:

  • O SDK mais antigo suportado pode mudar no futuro para a biblioteca específica
  • O bloco de erro try-catch é parte de um mecanismo maior de retorno. Alguns dispositivos específicos, embora devam suportar a biblioteca, lançam exceções. Eu pego VerifyError e todas as exceções para usar uma solução de fallback.

é muito útil pegar java.lang.AssertionError em um ambiente de teste …

Idealmente, não devemos lidar com erros. Mas pode haver casos em que precisamos fazer, com base no requisito de estrutura ou aplicativo. Digamos que eu tenha um daemon do XML Parser que implemente o analisador de DOM que consome mais memory. Se houver um requisito como o segmento do Analisador não deve ser perdido quando ele recebe o OutOfMemoryError , ele deve manipulá-lo e enviar uma mensagem / e-mail para o administrador do aplicativo / framework.

Idealmente, nunca devemos detectar Error em nosso aplicativo Java, pois é uma condição anormal. O aplicativo estaria em estado anormal e poderia resultar em um resultado muito errado.

Pode ser apropriado detectar erros em testes de unidade que verificam uma afirmação. Se alguém desabilitar afirmações ou excluir a afirmação que você gostaria de saber

Há um erro quando a JVM não está mais funcionando conforme o esperado ou está prestes a ser iniciada. Se você encontrar um erro, não há garantia de que o bloco catch será executado e, menos ainda, que ele será executado até o final.

Também dependerá do computador de corrida, o estado atual da memory, por isso não há como testar, tentar e fazer o seu melhor. Você só terá um resultado terrível.

Você também fará o downgrade da legibilidade do seu código.