Eai José, tranquilo?
- Realmente, a questão é que o compilador tem acesso a declaração de métodos e pode verificar se o método lança exceção e se essa é uma exceção é
checked
ou unchecked
, por exemplo:
public static void lancaExcecao() throws NullPointerException {
throw new NullPointerException();
}
Aqui temos uma questão que exceções do tipo unchecked
não precisam estar na assinatura do método, mas apenas para ficar mais didático eu coloquei
Em nosso main, podemos tranquilamente:
lancaExcecao();
Sem precisar adicionar um throws
ou try/catch
, pois o compilador sabe ao ler a assinatura do método que está sendo lançando uma exceção que ele não precisa lidar
Se mudarmos a nossa lancaExcecao
para uma simples Exception
, por exemplo:
public static void lancaExcecao() throws Exception {
throw new Exception();
}
Ai sim precisamos ter todo o tratamento, pois o compilador ao ler a assinatura do método vai perceber que há uma exceção que o usuário precisa tratar, então teoricamente podemos dizer que em nosso código a assinatura do método da uma pista, pois exceções derivadas de Runtime
não precisam declarar que lançam erros, enquanto as checkeds
obrigatoriamente precisam, e o compilador consegue analisar e fazer a verificação do nosso código :)
Agora em relação a dúvida 2 e 3 temos coisas que estão embutidas dentro da JVM e estão de formas realmente implícitas, mas também existem coisas relacionadas ao Sistema Operacional, então por exemplo (vou explicar de uma maneira beeem simples, mas existe um mundo enorme quando começamos a entender os sistemas operacionais:
No caso da divisão por zero, quando tentamos fazer essa operação na maioria das linguagens de programação, o que ocorre é que é emitido um sinal de interrupção para o sistema operacional derivado da nossa CPU, então o S.O pega esse erro e encaminha para a JVM que tem um tratador específico para esse sinal, e o tratamento pode ser simplesmente interromper o programa lançando uma exceção de ArithmeticException
Podemos ter algo parecido com o NullPointer
, talvez a JVM possa fazer uma verificação implícita para verificar a nulidade do objeto, mas também poderia trabalhar com uma memoria virtual, e ao tentar acessar um espaço de memória nulo teríamos um outro sinal de erro, que por sua vez contém outro "tratador" especifico, que em outras linguagens como C
é o famoso segment fault
Como eu disse existe um mundo enorme para entender mais afundo sobre como o Sistema Operacional lida com nossos programas, erros, e interrupções, mas alguns erros não necessariamente precisam estar explicitamente utilizando um throws
pois o próprio S.O ou a JVM pode fazer verificações e emitir sinais de que algo não está funcionando corretamente.
Abraços e Bons Estudos!!!