TRATAMENTO DE EXCEÇÕES NO DELPHI
Transcript of TRATAMENTO DE EXCEÇÕES NO DELPHI
-
1
TRATAMENTO DE EXCEES NO DELPHI
H algum tempo venho estudando detalhadamente o tratamento de excees
usando Try, Except, Finally e aps encontrar muita coisa igual na internet resolvi
escrever de forma objetiva o uso dessas clusulas ainda ignoradas por alguns
desenvolvedores. Nesse artigo no entrarei em detalhes histricos, j irei direto ao
ponto.
Objetivo desse artigo apresentar:
- Problemas que geram excees.
- Try, Finally com exemplos.
- Try, Except com exemplos.
- Try, Except com o tipo de exceo 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 ento, com outras do tipo: List
index out of bounds (-1), ou ainda Cannot make a visible window modal.
Essas mensagens no so geradas simplesmente pela sua Aplicao ou pelo Delphi,
na verdade, elas so excees no tratadas. Para entender melhor, exceo um
objeto definido pelo tipo Exception ou uma classe descedente. Sua funo
trabalhar especificamente nos casos de anormalidade que podem ocorrer na
Aplicao, exemplo: Se tentarmos acessar um ndice no existente no ListBox uma
anormalidade ser detectada pela exceo e uma mensagem ser mostrada.
Vejamos esse exemplo da forma prtica:
Aplicao
Cdigo - Evento OnClick() do Boto "Mostrar".
-
2
Com a aplicao em execuo a Exceo mostrada aps o clique no boto
"Mostrar"
Anlise
No Evento OnClick() do Boto "Mostrar" repare que existem duas linhas com
ShowMessage, mas a segunda linha nem chega a ser executada. Esse problema
ocorreu porque a Aplicao tentou acessar um ndice inexistente e assim, a exceo
detectou uma anormalidade na execuo do primeiro ShowMessage e retornou a
mensagem "List index out of bounds(-1)".
No Delphi devemos tratar esse tipo de problema utilizando as clusulas Try,
Except e Finally.
Try - Except - Finally
A clusula Try usada para iniciar um bloco que pode conter possveis erros. Se
um erro ocorrer, o programa no ser terminado. Instantaneamente, o Try deixa
de ser executado e d lugar a clusula Except ou Finally. Try pode ser usado em
inmeros trechos do cdigo, podendo at ser aninhado.
A clusula Except usada para iniciar um bloco caso uma exceo ocorra em Try.
Se o bloco que estiver em Except conter a exceo o programa no ser
terminado.
A clusula Finally usada para iniciar um bloco havendo problemas ou no com a
clusula Try.
Verso 1 - Try - Finally
Nos trechos de cdigo Try - Finally, a clusula Finally garante que todo o cdigo
contido em Finally ser executado independente ou no de problemas no cdigo
executado dentro da clusula Try. Em Try - Finally, Finally geralmente usado
para permitir limpeza de recursos alocados anteriormente.
Exemplo de Implementao
Try
-
3
// Trechos de Cdigo
Finally
// Trechos de Cdigo
End;
No exemplo abaixo uma diviso por Zero ocorre sem sucesso em Try exatamente
na linha "numero := 1 div zero;" gerando uma exceo que no tratada. Assim,
a linha "ShowMessage( 'numero / zero = ' + IntToStr( numero ) );" no
executada e o cdigo dentro da clusula finally executado.
Depois que o trecho de cdigo da clusula finally executado a exceo no
tratada retorna a mensagem:
Verso 2 - Try - Except
Nos trechos de cdigo Try - Except, somente se a clusula Try gerar uma exceo
que a clusula Except ser executada. Except usado para realizar ao
alternativa quando algo inesperado ocorrer em Try. A clusula Except por si s,
no pode determinar o tipo de erro encontrado.
Exemplo de Implementao
Try
-
4
// Trechos de Cdigo
Except
// Trechos de Cdigo
End;
No exemplo abaixo uma diviso por Zero ocorre sem sucesso em Try exatamente
na linha "numero := 1 div zero;" gerando uma exceo tratada com
"ShowMessage('Erro desconhecido encontrado!');". Assim, nenhuma
mensagem de exceo mostrada.
Resultado da exceo gerada no exemplo acima
No caso do Except podemos utilizar diferentes aes para diferentes tipos de
excees tais como EInOutError. Alm disso, a clusula else pode ser usada para
pegar todos os tipos de excees inesperadas, e o Tipo geral Exception usado
para pegar todos os tipos de excees. Atribuindo um nome exceo, o texto da
mensagem da exceo (Name.Message) pode ser obtido para a exibio, ou
ento, para outras finalidades.
Quando uma exceo aparece como no prximo exemplo, se a exceo no age
sobre sentenas On ou Else, ento uma checagem feita para ver se estamos num
bloco Try aninhado. Caso sim, a clusula Except do pai Try processada. Se no,
uma clusula On ou Else procurada, e o programa termina.
A clusula Else no realmente necessria - melhor usar On E:Exception Do, o
tratamento de exceo genrico, j que ele fornece a mensagem de erro
(E.Message).
Exemplo de Implementao
Try
-
5
// Trechos de Cdigo
Except
// E : Exception Do
On Nome : Tipo da Exceo Do
// Trechos de Cdigo
Else // opcional
// Trechos de Cdigo
End;
Nota: Voc pode determinar o tipo de erro que ocorreu usando a manipulao de
exceo genrica - On E:Exception Do. 'E' um ponteiro ao objeto Exception
criado pela condio de exceo.
No exemplo abaixo uma diviso por Zero ocorre sem sucesso em Try exatamente
na linha "numero := 1 div zero;" gerando uma exceo tratada de forma que o
tipo de exceo seja mostrada, linha on E : Exception do
ShowMessage(E.ClassName + 'erro gerado, com mensagem: ' +
E.Message');
Resultado da exceo gerada no exemplo acima
Antes de encerrarmos a primeira parte deixo alguns pontos importantes para
implementao do Try, except e finally em casos de tratamento de excees.
Pontos Importantes
Nunca construir tratamento de excees dessa forma:
-
6
Try
...
Except
...
Finally
...
End;
Forma correta de Aninhar tratamento de excees usando Try, Except, Finally:
Try
Try
...
Except
...
End;
Finally
...
End;
Encerramos aqui a primeira parte referente ao tratamento de excees, no prximo
tpico abordarei mais profundamente o tratamento de excees e tambm
apresentarei as listas de excees mostrando alguns exemplos. Espero que isso
possa ajudar, tambm espero que vocs possam contribuir com comentrios
referente a experincias obtidas com o uso do tratamento de excees. Dvidas
escrevam para Joo Marcos - [email protected]
Nesse artigo vou falar mais um pouco sobre: "Tratamento de Excees". Caso voc
no tenha lido o artigo anterior peo que no continue esse artigo a menos que
esteja bem inteirado sobre Tratamento de Excees. Se preferir, Clique aqui para
ver o artigo anterior.
Como, no artigo anterior vimos as clusulas Try, Except e Finally, nesse artigo
veremos exemplos de Try, Except e Finally aninhados e tambm apresentaremos
um meio de gerar excees atravs do Raise.
Download do Aplicativo de Teste. (Fonte dos exemplos mostrados aqui no artigo)
Para iniciar, vamos relembrar como tratar excees com as clusulas Try, Except e
Finally num determinado trecho do cdigo.
Nunca construir tratamento de excees dessa forma:
Try
...
Except
...
Finally
-
7
...
End;
Forma correta de tratar excees usando Try, Except, Finally:
Try
Try
...
Except
...
End;
Finally
...
End;
Podemos opcionalmente construir:
Try
Try
...
Except
...
End;
Finally
Try
...
Except
...
End;
...
End;
A seguir, apresento a lista das excees que descrevem os tipos bsicos - h
centenas de classes da exceo:
Classe - Descrio
Exception - Exceo genrica, usada apenas como ancestral de todas as outras
excees
EAbort - Exceo silenciosa, pode ser gerada pelo procedimento Abort e no
mostra nenhuma mensagem
EAccessViolation - Acesso invlido memria, geralmente ocorre com objetos
no inicializados
EConvertError - Erro de converso de tipos
EDivByZero - Diviso de inteiro por zero
EInOutError - Erro de Entrada ou Sada reportado pelo sistema operacional
EIntOverFlow - Resultado de um clculo inteiro excedeu o limite
EInvalidCast - TypeCast invlido com o operador as
EInvalidOp - Operao invlida com nmero de ponto flutuante
EOutOfMemory - Memria insuficiente
EOverflow - Resultado de um clculo com nmero real excedeu o limite
ERangeError - Valor excede o limite do tipo inteiro ao qual foi atribuda
-
8
EUnderflow - Resultado de um clculo com nmero real menor que a faixa
vlida
EVariantError - Erro em operao com variant
EZeroDivide - Diviso de real por zero
EDatabaseError - Erro genrico de banco de dados, geralmente no usado
diretamente
EDBEngineError - Erro da BDE, descende de EDatabaseError e traz dados que
podem identificar o erro
Exemplos:
1 - Nesse Exemplo, temos uma ocorrncia normal da Aplicao utilizando Try,
Finally -> Try, Except . O cdigo na clusula Try executado por completo e em
seguida, o cdigo da clusula Finally executado entrando primeiro na clusula
Try que est dentro de Finally, como no gerada nenhuma exceo dentro desse
Try o cdigo executado por completo indo em seguida para a ltima linha do
Finally.
2 - Nesse Exemplo, temos uma ocorrncia normal da Aplicao utilizando Try ->
Try, Except, Finally -> Try, Except. O cdigo na clusula Try -> Try
executado por completo e em seguida, o cdigo da clusula Finally executado
-
9
entrando primeiro na clusula Try que est dentro de Finally, como no gerada
nenhuma exceo dentro desse Try o cdigo executado por completo indo em
seguida para a ltima linha do Finally.
3 - Nesse Exemplo temos uma ocorrncia de uma diviso por zero na Aplicao
utilizando Try -> Try, Except, Finally -> Try, Except. O cdigo na clusula Try -
> Try executado at a linha "resultado := dividendo div divisor;", como nessa
linha ocorre a exceo "EDivByZero" o cdigo da clusula Except executado
verificando o tipo de exceo que foi gerado, repare que nesse exemplo o Except
possui apenas 3 tentativas (on EDivByZero do, on EAccessViolation do e else),
a tentativa vlida que ser executada on EDivByZero do e aps isso o finally
-
10
chamado executando o cdigo da mesma forma como mostramos nos exemplos
anteriores.
4 - Nesse Exemplo, temos a ocorrncia de um objeto que no criado, ou
instancializado se preferir, ser utilizado para atribuio de valor em Try -> Try,
Except, Finally -> Try, Except. O cdigo na clusula Try -> Try executado at
-
11
a linha "MinhaStringList.Text := '1';", como o objeto MinhaStringList no foi
criado ("MinhaStringList := TStringList.Create;"), essa linha gera a exceo
"EAccessViolation", ento, o cdigo da clsula Except executado verificando o
tipo de exceo que foi gerado, executando a linha on EAccessViolation do e
aps isso o finally chamado executando o cdigo da clusula Try que por sua
vez tambm gera uma exceo. A exceo ocorre porque tentamos destruir um
objeto que no foi Criado, linha "MinhaStringList.Destroy;". Assim o cdigo em
Except executado e aps isso o restante do cdigo do finally executado.
-
12
-
13
5 - Nesse Exemplo, temos uma ocorrncia parcialmente normal da Aplicao
utilizando Try -> Try, Except, Finally -> Try, Except. O cdigo na clusula Try -
> Try executado por completo e em seguida, o cdigo da clsula Finally
executado entrando primeiro na clsula Try que est dentro de Finally, quando a
linha "MinhaStringList.Destroy;" executada ocorre uma exceo porque
tentamos destruir um objeto que j havia sido destrudo, linha
"MinhaStringList.Destroy;" em Try -> Try. Assim o cdigo em Except
executado e aps isso o restante do cdigo do finally executado.
-
14
6 - Nesse Exemplo, temos uma ocorrncia parcialmente normal da Aplicao
utilizando Try, Finally -> Try, Except. O cdigo na clusula Try executado por
completo e em seguida, o cdigo da clsula Finally executado entrando primeiro
na clsula Try que est dentro de Finally, quando a linha
-
15
"MinhaStringList.Destroy;" executada ocorre uma exceo porque tentamos
destruir um objeto que j havia sido destrudo, linha "MinhaStringList.Destroy;"
em Try. Alm disso estamos forando a finalizao da Aplicao
"Application.Terminate;". Assim o cdigo em Except executado e o Raise
permite que a Exceo seja exibida ao usurio, ento, a Aplicao nem chega a
executar restante do cdigo do em finally.
Creio que o Raise pode ser usado de outras formas tambm, esse apenas um
exemplo.
7 - Nesse Exemplo, temos uma ocorrncia de uma diviso por zero na Aplicao
utilizando Try -> Try, Except, Finally. O cdigo na clusula Try -> Try
executado at a linha "resultado := dividendo div divisor;", como nessa linha
ocorre a exceo "EDivByZero" o cdigo da clsula Except executado, mas
dessa vez, sem verificar o tipo de exceo que foi gerado, porque diferente do
exemplo Nmero 3 que possuia 3 tentativas (on EDivByZero do, on
EAccessViolation do e else), o exemplo 7 mostra um tratamento genrico, linha
("on E : Exception do"). Dessa forma a Aplicao entende que qualquer exceo
ocorrida deve ser tratada pelo cdigo dentro de "on E : Exception do". Essa idia
-
16
pode ser aplicada a outros tipos de Excees, bastando apenas, voc definir um
tratamento genrico a todos os problemas que possam ocorrer.
Existem muitas formas de trabalhar com Tratamento de Excees de forma com
que a aplicao fique mais robusta. Um outro exemplo a possibilidade de criarmos
nossa prpria exceo.
Em type digite:
type
EUsuarioInvalido = class (Exception);
No evento OnClick do boto digite:
raise EUsuarioInvalido.Create('Usurio Invlido');
-
17
Em execuo:
Excees e o Debbuger
Enquanto voc estiver usando o Delphi para testar sua aplicao, ver que antes
das mensagens de tratamento de excees serem exibidas uma notificao de
Exceo da IDE exibida para voc (passando a impresso de que o tratamento de
exceo no funcionou), ento, pressionando a tecla F9 possvel dar continuidade
a aplicao. Mas as vezes isso fica sendo chato para testar nossa aplicao. No meu
caso acabei testando fora do Delphi rodando o executvel.
Para testar a aplicao sem que aparea a notifcao de Exceo da IDE do Delphi
faa o seguinte:
(Delphi 2006) -> Desmarque a opo Notify on language exceptions , no menu
Tools | Options | Debugger Options | Borland Debuggers | Language Exceptions .
Dessa forma as mensagens de exceo do depurador no sero mostradas.
Beleza galera, no prximo artigo irei passar mais alguns exemplos e apresentar
outros tipos de excees. Espero que isso possa ajudar, tambm espero que vocs
possam contribuir com comentrios referentes a experincias obtidas com o uso do
tratamento de excees. Dvidas escrevam para Joo Marcos -