tratamento de exceÇÕes no delphi

Upload: roklen

Post on 17-Oct-2015

122 views

Category:

Documents


1 download

TRANSCRIPT

  • 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 -

    [email protected].