Esse artigo faz parte da revista Clube Delphi edição 8. Clique aqui para ler todos os artigos desta edição


Atenção: por essa edição ser muito antiga não há arquivo PDF para download. Os artigos dessa edição estão disponíveis somente através do formato HTML. 

Tratando Erros com Exceções Parte I – Manipulando Exceções

 

Quando um erro ocorre em seu aplicativo, durante a execução, a aplicação chama uma exceção. Uma exceção é um objeto que contém informações sobre o erro ocorrido e onde ele ocorreu. Se você não especificar em seu código uma resposta ao erro, o Delphi mostrará uma mensagem descrevendo o erro.

O ideal seria que você pudesse tratar os erros ocorridos, evitando a perda de dados ou a necessidade de encerrar a aplicação. Além de tratar o erro a rotina de tratamento de erros poderia enviar ao usuário uma mensagem em português, mais significativa.

 

Obs: Quando você está no ambiente do Delphi, executa a aplicação e ocorre um erro, o Delphi lhe mostra uma mensagem de erro própria (independente da que você cria para manipular o erro). Você deve fechar esta caixa de mensagem e clicar um Run, para que a execução da aplicação continue. Só neste momento será mostrada a mensagem criada por você para manipular o erro. Quando você executa a aplicação fora do ambiente do Delphi, só a caixa de mensagem criada por você é mostrada.

 

Mensagem criada pelo usuário

 

O Delphi permite que você desenvolva aplicações robustas, ou seja, que tratam os erros ocorridos de forma que os dados não se percam. Para fazer uma aplicação robusta, é necessário que o código reconheça exceções quando elas ocorram, respondendo a elas.

 

Blocos Protegidos

Você cria uma resposta a uma exceção em um bloco de código, chamado de bloco protegido porque está resguardado de erros que podem parar a aplicação ou perder dados. Um bloco protegido começa com a palavra reservada try e termina com a palavra reservada end. Entre estas palavras você determina os comandos protegidos e a forma de reação a erros.

Quando você define um bloco protegido, especifica respostas a exceções que podem ocorrer dentro deste bloco. Se a exceção ocorrer, o fluxo do programa pula para a resposta definida, e após executá-la, abandona a bloco.

A forma mais simples para responder a uma exceção é garantir que algum código limpo é executado. Este tipo de resposta não corrige o erro, mas garante que sua aplicação não termine de forma instável. Normalmente, usamos este tipo de resposta para garantir a liberação de recursos alocados, mesmo que ocorra um erro. Para isto, usamos a estrutura try...finally...end.

Outra forma de se responder a uma exceção é tratando o erro, ou seja, oferecendo uma resposta específica para  um erro específico. Ao tratar o erro destruímos a exceção, permitindo que sua aplicação continue a rodar. Para isto, usamos a estrutura try...except...end.

 

A Estrutura Try...Finally..End

Seu código precisa garantir que, mesmo ocorrendo um erro, os recursos alocados sejam desalocados. Entre estes recursos estão: arquivos, memória, recursos do Windows, objetos.

 

Para garantir a desalocação dos recursos, usamos a estrutura abaixo:

 

{aloca os recursos}

try

{códigos que usam recursos}

finaly

{libera os recursos}

end;

 

A aplicação sempre executará os comandos inseridos na parte finally do bloco, mesmo que uma exceção ocorra. Quando um erro ocorre no bloco protegido, o programa pula para a parte finally, chamada de código limpo, que é executado. Mesmo que não ocorra um erro, estes comandos são executados.

 

Exemplo

A aplicação a seguir possui uma caixa de edição e um botão:

 

 

Ao entrarmos com o valor 0 na caixa de edição, e clicarmos no botão Calcular, geramos um erro, ao tentarmos dividir 10 por 0. Apesar do erro, o programa libera a memória alocada:

 

procedure Tform1.

Button1Click(Sender:Tobject);

var

   Apointer: Pointer;

   a, b: Integer;

begin

   a:=StrtoInt(Edit1.Text);

   GetMem(Apointer, 1024);

try

   b:=(10 div a);

   Edit1.Text:=IntToStr(b);

finally

   FreeMem(Apointer, 1024);

end;

end;

 

Exceções da RTL

Quando você escreve código que chama rotinas da biblioteca de run-time (RTL, run-time library), como funções matemáticas ou de manipulação de arquivos, os erros aparecem na forma de exceções. Por padrão, a RTL manda uma mensagem para o usuário, mas você pode tratar estes erros de outra forma.

As exceções geradas pela RTL são definidas na unit SysUtils, e todas descendem da classe Exception, que provê a string que aparece no quadro de mensagem da exceção.

Há diversos tipos de exceções geradas pela RTL, como por exemplo:

 

n exceções de entrada e saída;

n exceções de memória heap;

n exceções matemática envolvendo inteiros;

n exceções matemáticas envolvendo pontos flutuantes;

n exceções de typecast;

n exceções de conversão;

n exceções de hardware.

 

Você pode observar estas exceções com mais detalhes através do Object Browser, ativado através do comando View|Browser:

 

Exceções de Entrada e Saída

Ocorrem quando a RTL tenta acessar arquivos ou dispositivos de entrada e saída.

A unit SysUtils define uma exceção genérica de entrada e saída chamada EinOutError, que contém um atributo chamado ErrorCode que indica o erro ocorrido.

 

Exceções de Memória Heap

Ocorrem quando você tenta alocar ou acessar memória dinâmica. São definidos dois tipos de exceções: EoutOfMemory (indica que não há memória suficiente), e EinvalidPointer (ponteiro inválido).

 

Exceções Matemáticas para Inteiros

Ocorrem quando você realiza operações com números inteiros. A unit SysUtils define uma exceção genérica chamada EintError, com três tipos de exceções derivadas: EdividByZero (divisão por zero), ErangeError (número ou expressão fora da região), e EintOverflow (estouro na operação com inteiro).

 

Exceções de Pontos Flutuantes

Ocorrem quando são feitas operações com dados do tipo real. A unit SysUtils define uma exceção genérica chamada EmathError, com as seguintes exceções derivadas: EinvalidOp (procesador encontrou uma instrução indefinida), EzeroDivide (divisão por zero), Eoverflow, Eunderflow.

 

Exceções de Typecast

Ocorrem quando você tenta atribuir um objeto a um tipo inválido usando o operador as. Gera-se a exceção EinvalidCast quando isto ocorre.

 

Exceções de Conversão

Ocorrem quando se convertem dados de tipo para outro. A unit SysUtils define uma exceção chamada EconvertError quando isto ocorre, avisando que a conversão não pode ser feita.

 

Exceções de Hardware

Podem ocorrer em dois tipos de situação: quando o processador detecta uma falha, ou quando a aplicação gera uma interrupção intencional

Entre as exceções de hardware geradas temos: EaccessViolation (acesso ilegal de memória), EstackedOverflow (acesso ilegal ao seguimento stack do processador).

 

A Estrutura Try..Except..End

Um tratamento de exceção é um código que trata erros que ocorrem dentro de blocos protegidos.

Para definir um tratamento de exceção, utilize a seguinte construção:

 

try

{comandos que você deseja proteger}

except

{comandos de tratamento}

end;

 

A aplicação irá executar os comandos na parte except somente se ocorrer um erro. Se na parte try você chamar uma rotina que não trata erros, e um erro ocorrer, ao voltar para este bloco a parte except será executada. Uma vez que a aplicação localiza um tratamento para a exceção ocorrida, os comandos são executados, e o objeto exceção é destruído. A execução continua até o fim do bloco.

Dentro da parte except definimos um código a ser executado para manipular tipos específicos de exceção:

 

try

{comandos que você deseja proteger}

except

on Exceção do {código a ser executado de acordo com a exceção gerada}

end;

 

A palavra reservada on define respostas para uma exceção. On está sempre junto de do, para manipular a exceção.

 

Exemplo

A aplicação apresenta duas caixas de edição e um botão. Ao entrarmos com um número na primeira caixa de edição, este deve ser convertido para inteiro, e mostrando na segunda caixa.

 

 

Veja o código do botão Converter:

 

procedure Tform1.

Button1Click(Sender:tObject);

procedure TForm1.Button1Click(Sender: TObject);

var

   a: Integer;

begin

    try

       a:=StrtoInt(Edit1.Text);

       Edit2.Text:=IntToStr(a)

    except

    on EconvertError do

       Edit2.Text := '0';

end;

end;

 

Quando, ao executarmos a aplicação, inserimos na primeira caixa de edição o valor de 10,5 um erro é gerado, já que 10,5 não pode ser convertido para inteiro. Este erro é da classe EconvertError. Tratamos este erro, ao colocar na segunda caixa de edição o valor 0, quando o erro ocorre.