Escolar Documentos
Profissional Documentos
Cultura Documentos
1
Tratamento de exceções - parte 1
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
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.
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.
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:
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.
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');
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;
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.
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.
Para iniciar, vamos relembrar como tratar exceções com as cláusulas Try, Except e Finally num
determinado trecho do código.
Try
...
Except
...
Finally
...
End;
Try
Try
...
Except
...
End;
Finally
...
Tratamento de exceções
6
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);
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.
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:
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:
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ó.
raise EMinhaExcecao.Create(EmptyStr);
Assim estaremos provocando a exceção quando o botão for clicado e a seguinte mensagem vai
aparecer:
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.