Por que não precisamos adicionar try-catch a um RuntimeException?

Eu quero perguntar por que nós não temos que adicionar o bloco try-catch a um RuntimeException enquanto devemos fazer isso com outras exceções?

Quero dizer, como :

 public class Main { public static void main(String[] args) { throw new RuntimeException(); } } 

Edit: quando digo: throw new RuntimeException(); é tão claro que existe uma exceção, então por que o compilador não proíbe isso?

Isso é porque é uma exceção não verificada . Não precisa ser explicitamente declarado ou capturado. Veja também o tutorial da Sun sobre o assunto .

Atualização: em geral, você deve apenas lançar uma RuntimeException (preferencialmente uma de suas subclasss listadas no javadoc) para sinalizar que o chamador está fazendo errado. Ou seja, passar um argumento null (depois lançar NullPointerException ), ou um argumento ilegal (depois lançar IllegalArgumentException ), ou o método é chamado no momento / estado errado (depois lançar IllegalStateException ), etcetera. O chamador deve corrigir o código para evitar isso. Por exemplo, verificar antecipadamente se o argumento não é nulo, ou se o argumento está no formato / syntax correto, ou garantir que o método seja chamado no momento certo.

Se houver uma situação específica que deve lançar uma exceção de tempo de execução e você não pode usar uma de suas subclasss específicas, então você deve estendê-la e documentá-la adequadamente no javadoc da nova exceção e no método de chamada, por exemplo, ConfigurationException extends RuntimeException para o caso que o código de chamada não configurou o aplicativo / API corretamente antes de usar. Isso deve sinalizar o usuário final (o outro desenvolvedor) suficientemente para agir de acordo.

Resumindo: RuntimeExceptions deve identificar problemas recuperáveis ​​programaticamente causados ​​por falhas no stream de código ou na configuração (leia-se: falhas do desenvolvedor). As Exceptions verificadas devem identificar problemas recuperáveis ​​programaticamente que são causados ​​por condições inesperadas fora do controle de código (por exemplo, database inoperante, erro de E / S de arquivo, input incorreta do usuário final, etc). Errors devem identificar problemas de programação irrecuperáveis ​​(por exemplo, falta de memory, exceção dentro de um inicializador, etc).

RuntimeException , Error e suas subclasss não são especificamente verificadas em tempo de compilation – elas não fazem parte do contrato formal do método.

Veja o Capítulo 11 no JLS, Exceções, em particular 11.2, Verificação de Exceções em tempo de Compilação.

  • JLS, Ch. 11, exceções.

Vamos argumentar dessa maneira. E se o NullPointerException fosse projetado para ser uma exceção de tempo de compilation? Se tivesse sido feito, o compilador tinha que verificar estritamente se uma variável é nula ou não. Não há como isso poder ser feito.

 public void dummyMethod(Object obj){ } 

Aqui não há como o compilador verificar se o obj pode ser nulo ou não. No entanto, tem que haver algum erro / exceção tem que ser lançado quando você tem um cenário de ponteiro nulo.

Por especificação de idioma, as exceções não verificadas não são verificadas em tempo de compilation, o que significa que o compilador não requer methods para capturar ou especificar (com um throws ) eles. As classs pertencentes a esta categoria estão detalhadas na seção 11.2 Verificação em tempo de compilation de exceções do JLS:

As classs de exceções não verificadas são a class RuntimeException e suas subclasss e a class Error e suas subclasss . Todas as outras classs de exceção são classs de exceção verificadas . A API Java define várias classs de exceção, ambas verificadas e desmarcadas. Classes de exceção adicionais, tanto marcadas quanto desmarcadas, podem ser declaradas por programadores. Veja §11.5 para obter uma descrição da hierarquia de classs de exceção e algumas das classs de exceção definidas pela API Java e pela máquina virtual Java.

Então, como uma RuntimeException em uma exceção não verificada, o compilador não força você a lidar com isso. Se você quiser forçar o chamador de uma parte do código a manipular uma exceção, use uma exceção verificada (as subclasss de Exception diferente de RuntimeException são todas as classs de exceção verificadas).

Porque não é proibido lançar exceções de tempo de execução e você não precisa declarar exceções de tempo de execução. Seu programa é um programa Java válido, portanto, o compilador não tem motivos para reclamar.

Basicamente, uma exceção não identificada é apenas uma forma abreviada de exibir uma mensagem e encerrar o aplicativo.

Por que você precisaria fazer isso? Em alguns casos, você pode detectar que algo deu errado, algum arquivo não foi carregado, uma API está faltando, alguns dados estão corrompidos por algum motivo ou há um milhão de outras coisas erradas. Se você não lançar uma exceção, o aplicativo pode simplesmente travar em outro ponto ou, na pior das hipóteses, continuar em execução enquanto o erro aumenta, tornando muito mais difícil depurá-lo.

É importante entender que um lança uma exceção porque há um erro, a exceção não é o erro, é apenas o mensageiro.

A maioria das respostas neste fórum tem falado sobre a hierarquia de Exceções e o compilador Java não as pegou, mas eu tentaria responder a isso mais da perspectiva do design e por que talvez as coisas fossem projetadas assim.

Basicamente, quando você chama uma function (ou escreve algum código), uma exceção pode ser descartada com base em três situações diferentes:

  1. Baseado em uma condição inevitável como indisponibilidade de rede ou algum arquivo esperado ausente no sistema de arquivos.

  2. Baseado em uma condição evitável mas conhecida como Integer.parseInt(String) pode lançar NumberFormatException se o chamador passar uma string não Integer.parseInt(String) como "Hello" , mas o chamador pode assegurar validações apropriadas antes de passar qualquer string para a function e com a possibilidade de gerar a exceção. Um caso de uso comum pode estar validando a age campo de formulário em uma página da Web antes de transmiti-lo a camadas mais profundas que fazem a conversão.

  3. Uma condição desconhecida ou inesperada Toda vez que alguma linha de código pode lançar uma exceção em seu código porque houve algum engano que você fez e não observou a condição de erro até que ela explodisse na produção, geralmente acontece com NullPointer Reference , IndexOutOfBounds etc, que, se observado, possivelmente cairá na categoria 2.

As exceções da categoria 1 geralmente são projetadas como Checked Exceptions porque precisam impor a verificação de condições de erro inevitáveis ​​e impor seus fallbacks. Por exemplo, IOException é uma exceção verificada, porque no caso de você estar abrindo um arquivo, pode haver muitas coisas que podem dar errado (como o arquivo pode ser excluído, permissions etc.) e a pré-validação de todas elas pode ser muito incômoda.

Exceções do segundo tipo geralmente são modeladas como Unchecked Exceptions porque você pode ter sua pré-validação em vigor e pode ser irritante ser forçado a usar o try e pegar para situações que você já tenha cuidado.

Exceções do terceiro tipo não precisam ser nem mesmo preocupadas em geral, porque você não pode colocar o tratamento de erros em cada instrução do código do aplicativo que pode surgir inesperadamente. Mas às vezes você pode colocar um manipulador global, em algum lugar na pilha de chamadas, de onde quase todo o código do aplicativo é executado e manipulá-lo de uma maneira genérica para que seu aplicativo não trave devido a um erro inesperado.

Por exemplo, se você estiver executando um aplicativo da Web, poderá configurar seu Contêiner de Servlet para enviar um 500 Internal Server Error genérico para qualquer erro não manipulado em seu aplicativo. Ou, se você estiver executando um aplicativo Java autônomo, poderá manter o conteúdo do seu main method em um bloco try catch para evitar a falha do aplicativo.