Por que o Java não permite lançar uma exceção verificada de um bloco de inicialização estático? Qual foi o motivo por trás dessa decisão de design?
java
exception
static-initializer
desaparecido
fonte
fonte
Respostas:
Porque não é possível lidar com essas exceções verificadas na sua fonte. Você não tem controle sobre o processo de inicialização, e os blocos estáticos {} não podem ser chamados a partir de sua fonte, para poder envolvê-los com try-catch.
Como você não pode manipular nenhum erro indicado por uma exceção verificada, foi decidido proibir a execução de blocos estáticos de exceções verificadas.
O bloco estático não deve lançar exceções verificadas, mas ainda permite que exceções desmarcadas / em tempo de execução sejam lançadas. Mas, de acordo com as razões acima, você também não seria capaz de lidar com elas.
Resumindo, essa restrição impede (ou pelo menos dificulta) o desenvolvedor de criar algo que pode resultar em erros dos quais o aplicativo não pode se recuperar.
fonte
static { if(1 < 10) { throw new NullPointerException(); } }
Você pode solucionar o problema capturando qualquer exceção verificada e repetindo-a novamente como uma exceção não verificada. Esta classe de exceção desmarcada funciona bem como um invólucro:
java.lang.ExceptionInInitializerError
.Código de amostra:
fonte
catch (Exception e) {
vez disso.System.exit(...)
(ou equivalente) é sua única opção,Teria que se parecer com isso (este não é um código Java válido)
mas como o anúncio seria onde você o pegaria? As exceções marcadas requerem captura. Imagine alguns exemplos que podem inicializar a classe (ou não, porque ela já foi inicializada) e, apenas para chamar a atenção da complexidade que ela apresentaria, eu coloquei os exemplos em outro initalizador estático:
E outra coisa desagradável -
Imagine que a ClassA tinha um inicializador estático lançando uma exceção verificada: nesse caso, o MyInterface (que é uma interface com um inicializador estático "oculto") teria que lançar a exceção ou manipular - manipulação de exceção em uma interface? Melhor deixar como está.
fonte
main
pode lançar exceções verificadas. Obviamente, esses não podem ser manipulados.main()
que imprime a exceção com rastreamento de pilha paraSystem.err
e depois chamaSystem.exit()
. No final, a resposta para essa pergunta é provavelmente: "porque os designers de Java disseram isso".Tecnicamente, você pode fazer isso. No entanto, a exceção verificada deve ser capturada dentro do bloco. Uma exceção verificada não tem permissão para se propagar para fora do bloco.
Tecnicamente, também é possível permitir que uma exceção desmarcada se propague a partir de um bloco inicializador estático 1 . Mas é uma péssima idéia fazer isso deliberadamente! O problema é que a própria JVM captura a exceção não verificada e a agrupa e a repete como a
ExceptionInInitializerError
.NB: isso
Error
não é uma exceção regular. Você não deve tentar se recuperar dele.Na maioria dos casos, a exceção não pode ser capturada:
Em nenhum lugar você pode colocar um
try ... catch
no acima para capturar oExceptionInInitializerError
2 .Em alguns casos, você pode pegá-lo. Por exemplo, se você acionou a inicialização da classe chamando
Class.forName(...)
, poderá colocar a chamada em atry
e capturar aExceptionInInitializerError
ou a subsequenteNoClassDefFoundError
.No entanto, se você tentar se recuperar de um,
ExceptionInInitializerError
é provável que encontre um obstáculo. O problema é que, antes de lançar o erro, a JVM marca a classe que causou o problema como "falhou". Você simplesmente não será capaz de usá-lo. Além disso, quaisquer outras classes que dependem da classe com falha também entrarão em estado de falha se tentarem inicializar. O único caminho a seguir é descarregar todas as classes com falha. Isso pode ser viável para o código 3 carregado dinamicamente , mas em geral não é.1 - É um erro de compilação se um bloco estático lança incondicionalmente uma exceção não verificada.
2 - Você pode interceptá-lo registrando um manipulador de exceção não capturado padrão, mas isso não permitirá a recuperação, porque o encadeamento "principal" não pode ser iniciado.
3 - Se você quiser recuperar as classes com falha, precisará se livrar do carregador de classes que as carregou.
É para proteger o programador de escrever código que lança exceções que não podem ser manipuladas!
Como vimos, uma exceção em um inicializador estático transforma um aplicativo típico em um bloco. A melhor coisa que os designers de linguagem podem fazer é lidar com o caso verificado como um erro de compilação. (Infelizmente, não é prático fazer isso também com exceções não verificadas.)
OK, então o que você deve fazer se seu código "precisar" lançar exceções em um inicializador estático. Basicamente, existem duas alternativas:
Se a recuperação (completa!) Da exceção dentro do bloco for possível, faça isso.
Caso contrário, reestruture seu código para que a inicialização não ocorra em um bloco de inicialização estática (ou nos inicializadores de variáveis estáticas).
fonte
Dê uma olhada nas especificações da linguagem Java : afirma-se que é um erro de tempo de compilação se o inicializador estático
falhare conseguir concluir abruptamente com uma exceção verificada.fonte
public class Main { static { try{Class.forName("whathappenswhenastaticblockthrowsanexception");} catch (ClassNotFoundException e){throw new RuntimeException(e);} } public static void main(String[] args){} }
Saída:Exception in thread "main" java.lang.ExceptionInInitializerError Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: whathappenswhenastaticblockthrowsanexception at Main.<clinit>(Main.java:6) Caused by: java.lang.ClassNotFoundException: whathappen...
Como nenhum código que você escreve pode chamar bloco de inicialização estática, não é útil ativar a opção marcada
exceptions
. Se fosse possível, o que a jvm faria quando fossem lançadas exceções verificadas?Runtimeexceptions
são propagados.fonte
Por exemplo: DispatcherServlet do Spring (org.springframework.web.servlet.DispatcherServlet) lida com o cenário que captura uma exceção verificada e lança outra exceção não verificada.
fonte
Eu sou capaz de compilar lançando uma exceção marcada também ....
fonte