Você está na página 1de 14

Tratamento de exceções

1
Tratamento de exceções - parte 1

Há algum tempo venho estudando detalhadamente o tratamento de exceções


usando Try, Except, Finally e após encontrar muita coisa igual na internet resolvi escrever de forma
objetiva o uso dessas cláusulas ainda ignoradas por alguns desenvolvedores. Nesse artigo não entrarei
em detalhes históricos, já irei direto ao ponto.

Objetivo desse artigo é apresentar:


- Problemas que geram exceções.
- Try, Finally com exemplos.
- Try, Except com exemplos.
- Try, Except com o tipo de exceção especificado.

Repare a figura abaixo:

Eu tenho certeza que todos os desenvolvedores em algum momento da vida já se depararam com a
mensagem da figura acima, ou então, com outras do tipo: “List index out of bounds (-1)”, ou ainda
“Cannot make a visible window modal”. Essas mensagens não são geradas simplesmente pela sua
Aplicação ou pelo Delphi, na verdade, elas são exceções não tratadas. Para entender melhor, exceção é
um objeto definido pelo tipo Exception ou uma classe descedente. Sua função é trabalhar
especificamente nos casos de anormalidade que podem ocorrer na Aplicação, exemplo: Se tentarmos
acessar um índice não existente no ListBox uma anormalidade será detectada pela exceção e uma
mensagem será mostrada. Vejamos esse exemplo da forma prática:

Aplicação

Código - Evento OnClick() do Botão "Mostrar".

Com a aplicação em execução a Exceção é mostrada após o clique no botão "Mostrar"


Tratamento de exceções
2
Análise

No Evento OnClick() do Botão "Mostrar" repare que existem duas linhas com ShowMessage, mas a
segunda linha nem chega a ser executada. Esse problema ocorreu porque a Aplicação tentou acessar
um índice inexistente e assim, a exceção detectou uma anormalidade na execução do
primeiro ShowMessage e retornou a mensagem "List index out of bounds(-1)".

No Delphi devemos tratar esse tipo de problema utilizando as cláusulas Try, Except e Finally.

Try - Except - Finally

A cláusula Try é usada para iniciar um bloco que pode conter possíveis erros. Se um erro ocorrer, o
programa não será terminado. Instantaneamente, o Try deixa de ser executado e dá lugar a
cláusula Except ou Finally. Try pode ser usado em inúmeros trechos do código, podendo até ser
aninhado.
A cláusula Except é usada para iniciar um bloco caso uma exceção ocorra em Try. Se o bloco que
estiver em Except conter a exceção o programa não será terminado.
A cláusula Finally é usada para iniciar um bloco havendo problemas ou não com a cláusula Try.

Versão 1 - Try - Finally

Nos trechos de código Try - Finally, a cláusula Finally garante que todo o código contido
em Finally será executado independente ou não de problemas no código executado dentro da
cláusula Try. Em Try - Finally, Finally geralmente é usado para permitir limpeza de recursos alocados
anteriormente.

Exemplo de Implementação

Try
// Trechos de Código
Finally
// Trechos de Código
End;

No exemplo abaixo uma divisão por Zero ocorre sem sucesso em Try exatamente na linha "numero
:= 1 div zero;" gerando uma exceção que não é tratada. Assim, a linha "ShowMessage( 'numero /
zero = ' + IntToStr( numero ) );" não é executada e o código dentro da cláusula finally é
executado.
Tratamento de exceções
3

Depois que o trecho de código da cláusula finally é executado a exceção não tratada retorna a
mensagem:

Versão 2 - Try - Except

Nos trechos de código Try - Except, somente se a cláusula Try gerar uma exceção é que a
cláusula Except será executada. Except é usado para realizar ação alternativa quando algo inesperado
ocorrer em Try. A cláusula Except por si só, não pode determinar o tipo de erro encontrado.

Exemplo de Implementação
Try
// Trechos de Código
Except
// Trechos de Código
End;

No exemplo abaixo uma divisão por Zero ocorre sem sucesso em Try exatamente na linha "numero
:= 1 div zero;" gerando uma exceção tratada com "ShowMessage('Erro desconhecido
encontrado!');". Assim, nenhuma mensagem de exceção é mostrada.

Resultado da exceção gerada no exemplo acima

No caso do Except podemos utilizar diferentes ações para diferentes tipos de exceções tais
como EInOutError. Além disso, a cláusula else pode ser usada para pegar todos os tipos de exceções
inesperadas, e o Tipo geral Exception é usado para pegar todos os tipos de exceções. Atribuindo um
nome à exceção, o texto da mensagem da exceção (Name.Message) pode ser obtido para a exibição,
ou então, para outras finalidades.
Quando uma exceção aparece como no próximo exemplo, se a exceção não age sobre
sentenças On ou Else, então uma checagem é feita para ver se estamos num bloco Try aninhado.
Tratamento de exceções
4
Caso sim, a cláusula Except do pai Try é processada. Se não, uma cláusula On ou Else é procurada, e
o programa termina.
A cláusula Else não é realmente necessária - é melhor usar On E:Exception Do, o tratamento de
exceção genérico, já que ele fornece a mensagem de erro (E.Message).

Exemplo de Implementação

Try
// Trechos de Código
Except
// E : Exception Do
On Nome : Tipo da Exceção Do
// Trechos de Código
Else // opcional
// Trechos de Código
End;

Nota: Você pode determinar o tipo de erro que ocorreu usando a manipulação de exceção genérica
- On E:Exception Do. 'E' é um ponteiro ao objeto Exception criado pela condição de exceção.

No exemplo abaixo uma divisão por Zero ocorre sem sucesso em Try exatamente na linha "numero
:= 1 div zero;" gerando uma exceção tratada de forma que o tipo de exceção seja mostrada,
linha on E : Exception do ShowMessage(E.ClassName + 'erro gerado, com mensagem: ' +
E.Message');

Resultado da exceção gerada no exemplo acima

Antes de encerrarmos a primeira parte deixo alguns pontos importantes para implementação
do Try, except e finally em casos de tratamento de exceções.
Pontos Importantes
Nunca construir tratamento de exceções dessa forma:
Tratamento de exceções
5
Try
...
Except
...
Finally
...
End;

Forma correta de Aninhar tratamento de exceções usando Try, Except, Finally:

Try
Try
...
Except
...
End;
Finally
...
End;

Encerramos aqui a primeira parte referente ao tratamento de exceções, no próximo tópico abordarei
mais profundamente o tratamento de exceções e também apresentarei as listas de exceções
mostrando alguns exemplos. Espero que isso possa ajudar, também espero que vocês possam
contribuir com comentários referente a experiências obtidas com o uso do tratamento de exceções.

Tratamento de exceções - parte 2

Olá amigos leitores!

Nesse artigo vou falar mais um pouco sobre: "Tratamento de Exceções". Caso você não tenha lido o
artigo anterior peço que não continue esse artigo a menos que esteja bem inteirado sobre Tratamento
de Exceções. Se preferir, Clique aqui para ver o artigo anterior.
Como, no artigo anterior vimos as cláusulas Try, Except e Finally, nesse artigo veremos exemplos
de Try, Except e Finally aninhados e também apresentaremos um meio de gerar exceções através
do Raise.

Download do Aplicativo de Teste. (Fonte dos exemplos mostrados aqui no artigo)

Para iniciar, vamos relembrar como tratar exceções com as cláusulas Try, Except e Finally num
determinado trecho do código.

Nunca construir tratamento de exceções dessa forma:

Try
...
Except
...
Finally
...
End;

Forma correta de tratar exceções usando Try, Except, Finally:

Try
Try
...
Except
...
End;
Finally
...
Tratamento de exceções
6
End;

Podemos opcionalmente construir:


Try
Try
...
Except
...
End;
Finally
Try
...
Except
...
End;
...
End;

A seguir, apresento a lista das exceções que descrevem os tipos básicos - há centenas de classes da
exceção:
Classe - Descrição

Exception - Exceção genérica, usada apenas como ancestral de todas as outras exceções
EAbort - Exceção silenciosa, pode ser gerada pelo procedimento Abort e não mostra nenhuma
mensagem
EAccessViolation - Acesso inválido à memória, geralmente ocorre com objetos não inicializados
EConvertError - Erro de conversão de tipos
EDivByZero - Divisão de inteiro por zero
EInOutError - Erro de Entrada ou Saída reportado pelo sistema operacional
EIntOverFlow - Resultado de um cálculo inteiro excedeu o limite
EInvalidCast - TypeCast inválido com o operador as
EInvalidOp - Operação inválida com número de ponto flutuante
EOutOfMemory - Memória insuficiente
EOverflow - Resultado de um cálculo com número real excedeu o limite
ERangeError - Valor excede o limite do tipo inteiro ao qual foi atribuída
EUnderflow - Resultado de um cálculo com número real é menor que a faixa válida
EVariantError - Erro em operação com variant
EZeroDivide - Divisão de real por zero
EDatabaseError - Erro genérico de banco de dados, geralmente não é usado diretamente
EDBEngineError - Erro da BDE, descende de EDatabaseError e traz dados que podem identificar o
erro

Exemplos:

1 - Nesse Exemplo, temos uma ocorrência normal da Aplicação utilizando Try, Finally -> Try,
Except . O código na cláusula Try é executado por completo e em seguida, o código da
cláusula Finally é executado entrando primeiro na cláusula Try que está dentro de Finally, como não
é gerada nenhuma exceção dentro desse Try o código é executado por completo indo em seguida para
a última linha do Finally.
Tratamento de exceções
7

2 - Nesse Exemplo, temos uma ocorrência normal da Aplicação utilizando Try -> Try, Except, Finally
-> Try, Except. O código na cláusula Try -> Try é executado por completo e em seguida, o código da
cláusula Finally é executado entrando primeiro na cláusula Try que está dentro de Finally, como não
é gerada nenhuma exceção dentro desse Try o código é executado por completo indo em seguida para
a última linha do Finally.
Tratamento de exceções
8

3 - Nesse Exemplo temos uma ocorrência de uma divisão por zero na Aplicação utilizando Try -> Try,
Except, Finally -> Try, Except. O código na cláusula Try -> Try é executado até a linha "resultado
:= dividendo div divisor;", como nessa linha ocorre a exceção "EDivByZero" o código da
cláusula Except é executado verificando o tipo de exceção que foi gerado, repare que nesse exemplo
o Except possui apenas 3 tentativas (on EDivByZero do, on EAccessViolation do e else), a
tentativa válida que será executada é on EDivByZero do e após isso o finally é chamado executando
o código da mesma forma como mostramos nos exemplos anteriores.

4 - Nesse Exemplo, temos a ocorrência de um objeto que não criado, ou instancializado se preferir, ser
utilizado para atribuição de valor em Try -> Try, Except, Finally -> Try, Except. O código na
Tratamento de exceções
9
cláusula Try -> Try é executado até a linha "MinhaStringList.Text := '1';", como o
objeto MinhaStringList não foi criado ("MinhaStringList := TStringList.Create;"), essa linha gera a
exceção "EAccessViolation", então, o código da clásula Except é executado verificando o tipo de
exceção que foi gerado, executando a linha on EAccessViolation do e após isso o finally é chamado
executando o código da cláusula Try que por sua vez também gera uma exceção. A exceção ocorre
porque tentamos destruir um objeto que não foi Criado, linha "MinhaStringList.Destroy;". Assim o
código em Except é executado e após isso o restante do código do finally é executado.
Tratamento de exceções
10

5 - Nesse Exemplo, temos uma ocorrência parcialmente normal da Aplicação utilizando Try -> Try,
Except, Finally -> Try, Except. O código na cláusula Try -> Try é executado por completo e em
seguida, o código da clásula Finally é executado entrando primeiro na clásula Try que está dentro
de Finally, quando a linha "MinhaStringList.Destroy;" é executada ocorre uma exceção porque
tentamos destruir um objeto que já havia sido destruído, linha "MinhaStringList.Destroy;" em Try -
> Try. Assim o código em Except é executado e após isso o restante do código do finally é
executado.
Tratamento de exceções
11
6 - Nesse Exemplo, temos uma ocorrência parcialmente normal da Aplicação utilizando Try, Finally ->
Try, Except. O código na cláusula Try é executado por completo e em seguida, o código da
clásula Finally é executado entrando primeiro na clásula Try que está dentro de Finally, quando a
linha "MinhaStringList.Destroy;" é executada ocorre uma exceção porque tentamos destruir um
objeto que já havia sido destruído, linha "MinhaStringList.Destroy;" em Try. Além disso estamos
forçando a finalização da Aplicação "Application.Terminate;". Assim o código em Except é executado
e o Raise permite que a Exceção seja exibida ao usuário, então, a Aplicação nem chega a executar
restante do código do em finally.
Creio que o Raise pode ser usado de outras formas também, esse é apenas um exemplo.

7 - Nesse Exemplo, temos uma ocorrência de uma divisão por zero na Aplicação utilizando Try -> Try,
Except, Finally. O código na cláusula Try -> Try é executado até a linha "resultado := dividendo
div divisor;", como nessa linha ocorre a exceção "EDivByZero" o código da clásula Except é
executado, mas dessa vez, sem verificar o tipo de exceção que foi gerado, porque diferente do
exemplo Número 3 que possuia 3 tentativas (on EDivByZero do, on EAccessViolation do e else),
o exemplo 7 mostra um tratamento genérico, linha ("on E : Exception do"). Dessa forma a Aplicação
entende que qualquer exceção ocorrida deve ser tratada pelo código dentro de "on E : Exception do".
Essa idéia pode ser aplicada a outros tipos de Exceções, bastando apenas, você definir um tratamento
genérico a todos os problemas que possam ocorrer.
Tratamento de exceções
12

Existem muitas formas de trabalhar com Tratamento de Exceções de forma com que a aplicação fique
mais robusta. Um outro exemplo é a possibilidade de criarmos nossa própria exceção.

Em type digite:

type
EUsuarioInvalido = class (Exception);

No evento OnClick do botão digite:

raise EUsuarioInvalido.Create('Usuário Inválido');

Em execução:

Exceções e o Debbuger

Enquanto você estiver usando o Delphi para testar sua aplicação, verá que antes das mensagens de
tratamento de exceções serem exibidas uma notificação de Exceção da IDE é exibida para você
(passando a impressão de que o tratamento de exceção não funcionou), então, pressionando a tecla F9
é possível dar continuidade a aplicação. Mas as vezes isso fica sendo chato para testar nossa aplicação.
Tratamento de exceções
13
No meu caso acabei testando fora do Delphi rodando o executável.
Para testar a aplicação sem que apareça a notifcação de Exceção da IDE do Delphi faça o seguinte:
(Delphi 2006) -> Desmarque a opção “Notify on language exceptions ”, no menu Tools | Options |
Debugger Options | Borland Debuggers | Language Exceptions . Dessa forma as mensagens de
exceção do depurador não serão mostradas.

Beleza galera, no próximo artigo irei passar mais alguns exemplos e apresentar outros tipos de
exceções. Espero que isso possa ajudar, também espero que vocês possam contribuir com comentários
referentes a experiências obtidas com o uso do tratamento de exceções.

Tratamento de exceções - parte final

Olá amigos leitores!

Esse é o último artigo e vou encerrar o assunto sobre: "Tratamento de Exceções". Caso você não tenha
lido os artigos anteriores peço que não continue esse artigo a menos que esteja bem inteirado sobre
Tratamento de Exceções. Se preferir, Clique aqui para ver o primeiro artigo, ou clique aqui para ver o
Segundo so Tratamento de Exceções.
Nesse artigo apenas vou adicionar um complemento referente aos artigos anteriores mostrando outros
exemplos.

Download do Aplicativo de Teste. (Fonte dos exemplos mostrados nesse artigo e no artigo anterior)

Observação: Dessa vez não entrarei em datalhes de exceções como por exemplo: exceções
da RTL (Run Time Libray) ou da VCL (Visual Component Library), mesmo porque o Delphi
está sendo atualizado constantemente, sendo assim, teria que especificar quais exceções
pertencem a qual versão e etc.

Exceções Silenciosas

Com o Comando Abort é possível gerar Exceções Silenciosas que não exibem mensagem alguma,
exemplo:

Manipulando Exceções em TApplication

Quando ocorre uma exceção e essa não é tratada usando Try, Except e Finally, será passada ao
manipulador de exceções do objeto Application, mais exatamente no Evento OnException. Até o Delphi
Tratamento de exceções
14
4 os usuários precisavam criar métodos para utilizar no evento OnException do objeto Application. A
partir do Delphi 5 podemos codificar o Evento OnException do Objeto ApplicationEvents da paleta
Additional. Ele pode ser utilizado para manipular as exceções do sitema, veja um exemplo de como
criar exceções personalizadas usando ApplicationEvents:

Application Events da paleta Additional.

Manipulando Passo-a-Passo

Abra uma nova aplicação e nela insira um botão (TButton da Paleta Standard) e um Application
Events (TApplicationEvents da Additional). Pressione F12 e vá até type e insira a
linha EMinhaExcecao = class (Exception);, conforme a figura a seguir.

Após isso selecione Application Events e de um duplo clique no evento OnException e cole o código
abaixo:
if ( E is EMinhaExcecao ) then
Application.MessageBox('Minha Exceção ta personalizada','Tratamento de Exceções', MB_OK
+ MB_ICONINFORMATION + MB_DEFBUTTON2);

Esse código nada mais é do que minha exceção personalizada da forma como quero exibir quando
acontecer a exceção EMinhaExcecao. É claro que nesse caso nós provocaremos essa exceção, porque
senão ela nunca acontecerá por si só.

No evento OnClick do botão cole o código abaixo:

raise EMinhaExcecao.Create(EmptyStr);

Assim estaremos provocando a exceção quando o botão for clicado e a seguinte mensagem vai
aparecer:

Download desse exemplo. Clique aqui.

Usando o recurso acima é possível tratar as exceções de forma global, personalizando todas as
possíveis exceções de seu projeto.

Quero aproveitar para pedir desculpas a Marku Vinicius Da Silva, referente a exceções ADO.
Eu não consegui encontrar nenhum material específico sobre exceções desses componentes.

Mas como já nos falamos anteriormente você pode usar E: Exception para qualquer tipo de exceção
que ocorra, claro que isso pode não ser totalmente eficaz, mas irá ajudar.

Você também pode gostar