Todo iniciante em Java (assim como um dia fui, e ainda sou em determinados assuntos) não consegue compreender a importância que existe por trás do uso de Exceptions. Para falar bem a verdade, não só iniciantes, mas profissionais “experientes” utilizam este recurso de forma deturbada, resultando em um código final não só incompreensível, mas o que pode ser considerado ainda pior, impossível de se realizar manutenções rapidamente, atrelado ainda ao fato de que fatalmente códigos escritos com uso incorreto das Exceptions, são códigos que não passaram por testes unitários automatizados com o jUnit por exemplo, mas se passaram, foi de maneira incorreta ou mal realizada.
Como realmente utilizar bem as exceptions então? De acordo com a sugestão da Sun, observamos que a definição de exception é:
An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program’s instructions.
Esta frase curta nos dá um rumo muito grande sobre as exceptions: elas devem nortear todas as possibilidades de execução de um método. Imaginemos o seguinte requisito:
Um método deve realizar uma consulta em uma tabela de auditoria de acessos, dado um determinado período de tempo. Poderíamos compor este método em uma interface da seguinte maneira :
List<TraceAuditoria> listarAcessosPeriodo(Calendar dataInicial, Calendar dataFinal);
Bastante simples, assim como deve ser. Mas o que este método deveria fazer, caso os argumentos informados não sejam os adequados? Imaginemos por exemplo, que o cliente deste método informou uma data inicial maior que a data final, o que nunca poderia acontecer? Fatalmente, a consulta seria realizada no banco e não retornaria nenhum registro, mas consumiria ciclos de processamentos desnecessários, dentre outros problemas.
OK, precisaríamos ter a certeza de que a data inicial não é maior que a final, mas ao mesmo tempo, precisamos garantir aos clientes de nosso método, que eles tenham o conhecimento de que existem regras para sua execução. Neste ponto, estipulamos um contrato de execução, na qual o método indica: informe os parâmetros que solicito, e o resultado será o estipulado em meu retorno, mas minhas regras para tal serão as seguintes MinhaListaDeExceptions.
Como primeira regra do cenário exemplificado, indicamos que a data inicial não pode ser maior que a data final. Nosso método, deveria então ser assinado da seguinte maneira:
List<TraceAuditoria> listarAcessosPeriodo(Calendar dataInicial, Calendar dataFinal) throws DataInicialMaiorQueFinalException;
Muito melhor agora. Declaramos explicitamente para o mundo externo (clientes que invocarão nossos métodos) que não iremos aceitar datas iniciais maiores que datas finais. Assim como esta, outras exceções poderiam ser agregadas à assinatura do método, como por exemplo PeriodoInformadoMaiorQueLimiteException, caso este étodo não aceite um período de datas muito longo para consulta, ou então DataFinalMaiorQueAtualException, para indicar a nossos clientes que nosso método não aceitará uma data futura para consulta.
Em primeiro momento, o código que invoca um método que atira exceções, como nosso exemplo, parece irritantemente maior e mais chato de se usar, mas com o tempo, e com as manutenções se tornano mais fáceis e claras, o uso de exceções para ditar regras torna-se um hábito. Além disso, testes unitários (com jUnit por exemplo) tornam-se muito legais de se fazer.
Você pode notar que estou me referindo a a checked Exceptions, ou seja, exceções que são de tratamento obrigatório por parte dos clientes dos métodos e é este o melhor uso delas em minha opinião: informar sobre problemas conhecidos, problemas que quero evitar e que não podem ser aceitos por minah execução. Não sou favorável ao uso de unchecked exceptions nesses casos, utilizo-as com maior frequência para problemas totalmente desconhecidos, ou falando melhor, problemas em que meu código nada pode fazer para alcançar uma solução momentânea. Citando este tipo de Exception, todas as vezes em que elas ocorrem em codificações que realizo, as transformo em uma checked exception com o nome de minha classe e mando de volta à meu cliente. Este último caso, utilizo com frequência em classes de acesso à bancos de dados, que possuem uma possibilidade imensa de problemas que nada podemos fazer (queda de banco, queda de comunicação, problemas com drivers e etc) , a não ser cancelar a solicitação. Mas não podemos simplesmente (como infelizmente já vi muito) atirar uma exceção genérica chamada BusinessException e tudo certo! Como descobrir um possível erro em produção depois? Como descobrir rapidamente quem atirou esta exceção? Impossível em um piscar de olhos… O que faço, para exemplificar, é o seguinte:
public class UsuarioDAO {
public boolean persist (Usuario u) throws MinhaListaDeExceptions, UsuarioDAOException {
}
}
A exception destacada em negrito, nada mais é do que uma fachada para identificar erros que não são de tratamento possível, mas sim de acontecimentos inesperados, em que houve problemas de rede (permanentes ou não) ou qualquer outra coisa externa à nossa execução. Acontecendo alguma coisa deste tipo, saberemos exatamente qual classe atirou a exceção, poderemos resolver nossos problemas de produção com muito mais agilidade.
Então é isso… Utilize Exceptions para definir o contrato de seus métodos e construtores com frequência. Seu trabalho melhora, sua confiança em seu código melhora e seus problemas diminuem. Fuja de BusinessException, cuidado com os problemas inesperados e saiba acima de tudo, registrá-los aos clientes de seu código de forma a evitar dores de cabeça quando seu sistema estiver no ar!
Março 28, 2008 em 12:49 pm
Fugindo um pouco do assunto, tenho uma dúvida
Tenho uma aplicação em java que roda em duas lojas diferentes, quando faço qualquer atualização na aplicação tenho que ir até a loja, baixar pelo svn as atualizações, esperar a loja fechar e fazer o deploer.
Pergunta: Em uma aplicação desctop(swing) cliente-servidor como fazer a atualização da aplicação, de forma automática ou com a menor interação possível do usuário, quando o aplicação encontra-se em uso continuo em localidade diferente?