Exceções em tempo de execução são detectadas apenas durante a execução do programa e geralmente não exigem tratamento explícito. Essas são conhecidas como exceções unchecked.
Exceções verificadas podem ser determinadas durante a compilação e exigem que o desenvolvedor implemente um mecanismo de tratamento adequado.
As exceções verificadas incluem tipos comuns como exceções de E/S e exceções SQL. Para esses tipos de exceções, o compilador Java obriga o desenvolvedor a implementar blocos de captura usando catch. Consequentemente, mesmo que não desejemos, somos forçados a escrever múltiplos blocos catch para lidar com possíveis falhas.
As exceções de tempo de execução, também chamadas de exceções em tempo de execução, podem ser deixadas sem tratamento. Quando ocorrem, a máquina virtual assume o controle. Um exemplo clássico é a exceção NullPointerException, que raramente vemos sendo tratada explicitamente, apesar de ser uma das mais comuns.
Quando exceções em tempo de execução não são tratadas pelo programador, elas resultam em erros diretos na execução. Se forem tratadas com try/catch/finally, as exceções serão capturadas e manipuladas.
Por exemplo, o método a seguir retornará o valor 7:
</div>No desenvolvimento de programas, os fluxos de dados seguem padrões predefinidos. Se a interação entre usuário e aplicativo funcionar exatamente conforme planejado, o sistema operará sem problemas. Podemos assumir que todos os dados estarão em conformidade com os requisitos, que as validações de interface estarão corretas e que todos os recursos estarão disponíveis. No entanto, para garantir a segurança do sistema, devemos lidar com potenciais riscos e não manter expectativas idealizadas sobre a integridade dos dados.
No ambiente ASP.NET, o tratamento de erros opera em dois níveis: validação de entrada no nível da página e o mecanismo estruturado de tratamento de erros fornecido pelo CLR.
Na validação de informações na página, podemos usar scripts como JavaScript ou VBScript, ou utilizar os recursos de validação e expressões regulares integrados ao .NET para verificar formatos antes do envio e processamento. Essas verificações incluem endereços de rede, e-mails, comprimento de strings e tipos de dados.
O tratamento estruturado de exceções é um componente fundamental do CLR, caracterizado por: suporte multiplataforma, permitindo que exceções sejam lançadas em uma linguagem e capturadas em outra; e tratamento em camadas, onde uma exceção pode conter outras exceções, permitindo que sistemas capturem exceções de camadas inferiores e lancem suas próprias exceções, mantendo as informações das originais.
O tratamento estruturado de exceções normalmente envolve três componentes:
(1) **Try**: a parte do código onde podem ocorrer erros.
(2) **Catch**: a seção responsável por tratar diferentes tipos de erros (podendo haver múltiplos blocos). Os blocos `catch` devem ser ordenados corretamente, com exceções mais específicas aparecendo primeiro. Quando há relações de herança entre exceções, as classes filhas devem vir antes das classes base.
(3) **Finally**: código destinado à liberação de recursos ou operações de limpeza que devem ocorrer após o bloco `try` (opcional). O bloco `finally` é executado independentemente de ocorrer ou não uma exceção.
As exceções fazem parte inevitável do design de programas, e aplicações bem projetadas devem ser capazes de lidar com todos os erros potenciais. É essencial considerar abrangentemente o tratamento de exceções, envolvendo todo código suscetível em blocos `try` e estabelecendo mecanismos próprios de tratamento, categorizando as respostas conforme o tipo de exceção.
Quando ocorre uma exceção, é importante identificar sua causa raiz e obter informações relevantes. Devemos lançar exceções específicas de acordo com as circunstâncias reais, criar mecanismos de captura e responder adequadamente quando as exceções forem detectadas. Durantee o desenvolvimento, podemos instanciar e lançar exceções tanto do sistema quanto personalizadas. Por exemplo, para interfaces impossíveis de implementar, podemos lançar `System.NotSupportedException` para informar o chamador.
Ao tratar exceções, devemos processar cada tipo específico em seus respectivos blocos `catch`, caso contrário o programa será encerrado. Cada tipo de exceção deve ser tratado de forma diferente, evitando respostas uniformes para todos os casos. Quando ocorre uma exceção, devemos fornecer ao usuário uma mensagem amigável (usuários finais não entendem detalhes técnicos de exceções, então precisamos oferecer informações relevantes, soluções ou instruções para contatar administradores), e quando possível, ofereecr opções (como confirmar ou cancelar) para que o usuário decida o comportamento do sistema. Além disso, as exceções devem ser registradas em log. Nem todas as exceções precisam ser registradas, especialmente aquelas que já foram capturadas e tratadas automaticamente.
Podemos registrar exceções das seguintes formas:
Armazenamento em arquivos: facilita a visualização por técnicos e permite melhorias futuras no programa.
Armazenamento em banco de dados: suporta consultas, permitindo posterior categorização, busca e gerenciamento das exceções.
Registro no EventLog: permite operações remotas e facilita o monitoramento de exceções em múltiplas máquinas por administradores de sistema.
Além das exceções previstas, existem aquelas imprevisíveis. Esse tipo de exceção não pode ser gerenciado diretamente e, quando ocorre, o programa deve ser redirecionado para uma página de erro específica, informando o usuário sobre a falha e encerrando a aplicação. Manter bons registros de log traz muitas vantagens para resolução e depuração de problemas. Devemos evitar o uso de `try-catch` sem tratamento real das exceções, pois isso equivale a liberar as falhas (sendo pior do que não capturar).
No tratamento de exceções, devemos observar que o bloco `finally` é responsável por liberar recursos, restaurar configurações e outras tarefas de encerramento. A estrutura básica é:
try { int valor = 456/0; // lança exceção de divisão por zero } catch { // ... // captura e trata a exceção } finally { // ... // realiza limpeza final ou outras operações }
O tratamento de exceções deste capítulo se aplica a áreas propensas a erros (como operações de banco de dados), mas limita-se a mostrar mensagens de erro ao usuário após capturar exceções SQL, sem implementar tratamentos adicionais.
Classes de exceção comuns em C#:
Exception: classe base para todos os objetos de exceção.
SystemException: classe base para todos os erros ocorridos em tempo de execução.
IndexOutOfRangeException: lançada em tempo de execução quando um índice de array está fora dos limites.
NullReferenceException: lançada em tempo de execução quando um objeto nulo é referenciado.
InvalidOperationException: lançada por alguns métodos quando chamadas não são válidas para o estado atual do objeto.
ArgumentException: classe base para todas as exceções relacionadas a argumentos.
ArgumentNullException: lançada por métodos quando um argumento é nulo (não permitido).
ArgumentOutOfRangeException: lançada por métodos quando um argumento está fora de um intervalo especificado.
InteropException: classe base para exceções que ocorrem fora do ambiente CLR.
ComException: exceção contendo informações HRESULT de classes COM.
SEHException: encapsula informações do tratamento estruturado de exceções Win32.
SqlException: encapsula exceções de operações SQL.