Agora, acho que ela quis te explicar a seguinte situação: imagine que você tem o seguinte método, que insere um nome numa tabela de nomes do banco de dados:
public insereNome(String nome) {
Statatement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO nomes(nome) VALUES('" + nome + "')");
stmt.close();
}
Da forma que está, esse método aí em cima não compila. Por quê? Simplesmente porque os métodos executeQuery e close da classe Statement lançam a exceção verificada SQLException. Veja, o problema aqui é tratar exceções lançadas, e não gerar nossas próprias exceções (como no caso que estava sendo discutido no tópico).
Para isso, temos duas alternativas. A primeira, é colocar um bloco try, catch e realmente tratar a exceção. Algo do tipo:
public insereNome(String nome) {
try {
Statatement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO nomes(nome) VALUES('" + nome + "')");
stmt.close();
} catch (SQLException e) {
log.getInstance().severe("Exceção inexperada!", e);
System.exit(0); //Aborta a aplicação
}
}
O tratamento acima é um tanto drástico. Ele loga a exceção em algum arquivo, e depois aborta o programa. No nível em que essa classe está, não teria como fazer um tratamento muito mais sofisticado do que isso. O mais adequado seria partir para outra alternativa.
A outra alternativa, seria deixar para a classe que está usando nosso método tratar a exceção. Nesse caso, não nos preocuparíamos com a SQLException nesse método, mas nas classes que fazem uso desse método. Acho que era essa situação que estava no slide de sua professora.
Fazemos isso com a cláusula throws:
public insereNome(String nome) throws SQLException {
Statatement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO Nomes(nome) VALUES('" + nome + "')");
stmt.close();
}
Muito similar ao código original, não? Mas a cláusula throws, na assinatura do método, agora forcará a quem usar o método inserirNome a também usar um try catch, ou continuar lançando a exceção para cima, com outro throws. Embora nesse método não tenhamos mais que nos preocupar com a SQLException (conforme disse sua professora), ainda teremos que nos preocupar com ela no futuro, quando usarmos o método inserirNome.
Agora, nem sempre repassar diretamente a exceção é uma boa idéia. É uma boa prática de programação lançar exceções adequadas a camada que você estiver trabalhando. No caso do exemplo acima, nosso método ficaria:
public insereNome(String nome) throws FalhaAoInserirNomeException {
try {
Statatement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO Nomes(nome) VALUES('" + nome + " ')");
stmt.close();
} catch (SQLException e) {
throw new FalhaAoInserirNomeException("Não foi possível inserir o nome " + nome, e);
//Note que o segundo parâmetro é a exceção lançada.
//É uma boa prática anexar a causa na exceção reescrita.
}
}
Parece um mix dos dois, não? Mas, você poderia decidir que FalhaAoInserirNomeException não é uma exceção comum e que, portanto, seria uma RuntimeException. As classes que usam sua classe não precisariam mais captura-la, embora ela ainda ocorresse em caso de problemas e seria logada em algum ponto da aplicação, provavelmente por um UncaughtExceptionHandler.
Qual dos três casos é o mais adequado? Depende. O ideal é que você pare e pense em qual das três alternativas mais se encaixa no momento do tratamento da sua exceção.
Agora, quando o assunto é lançar suas próprias exceções, o throws não vai te ajudar em muita coisa. A não ser ao documentar que sua classe lança essa ou aquela exceção.
Agora uma coisa que você nunca deve fazer é o seguinte código:
try {
//Código que lança exceção
} catch (Exception e) {
e.printStackTrace();
}
Isso aí ignorará todas as exceções, sejam elas runtime ou não. Uma péssima idéia. Seu código poderá executar algo inválido e continuará prosseguindo, simplesmente imprimindo o erro, mas ignorando que ele ocorreu. Isso certamente gerará problemas maiores.
Na pior das hipóteses, faça:
try {
//Código que lança exceção
} catch (Exception e) {
throw new RuntimeException(e);
}
Pelo menos assim, você deixa de se preocupar com a exceção, mas não deixa de lança-la, ainda que sem a necessidade de captura-la. Quando possível, parta para uma das três primeiras alternativas.
E note que, de novo, colocamos como parâmetro da RuntimeException a exceção original. Novamente para indicar a causa. Isso é muito importante no log que será gerado, especialmente se o problema ocorrer em campo.