excessões try, except, finally

19
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".

Upload: renato-grova

Post on 23-Jul-2015

73 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: Excessões TRY, EXCEPT, FINALLY

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"

Page 2: Excessões TRY, EXCEPT, FINALLY

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.

Page 3: Excessões TRY, EXCEPT, FINALLY

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çãoTry// Trechos de CódigoExcept// Trechos de CódigoEnd;

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.

Page 4: Excessões TRY, EXCEPT, FINALLY

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. 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ódigoExcept// E : Exception Do On Nome : Tipo da Exceção Do// Trechos de CódigoElse // opcional // Trechos de CódigoEnd;

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.

Page 5: Excessões TRY, EXCEPT, FINALLY

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 ImportantesNunca construir tratamento de exceções dessa forma:

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

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

TryTry...Except

Page 6: Excessões TRY, EXCEPT, FINALLY

...End;Finally...End;

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:

TryTry...Except...End;Finally...End;

Podemos opcionalmente construir:TryTry...Except...End;FinallyTry...Except...End;...

Page 7: Excessões TRY, EXCEPT, FINALLY

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çõesEAbort - Exceção silenciosa, pode ser gerada pelo procedimento Abort e não mostra nenhuma mensagemEAccessViolation - Acesso inválido à memória, geralmente ocorre com objetos não inicializadosEConvertError - Erro de conversão de tiposEDivByZero - Divisão de inteiro por zeroEInOutError - Erro de Entrada ou Saída reportado pelo sistema operacionalEIntOverFlow - Resultado de um cálculo inteiro excedeu o limiteEInvalidCast - TypeCast inválido com o operador asEInvalidOp - Operação inválida com número de ponto flutuanteEOutOfMemory - Memória insuficienteEOverflow - Resultado de um cálculo com número real excedeu o limiteERangeError - Valor excede o limite do tipo inteiro ao qual foi atribuídaEUnderflow - Resultado de um cálculo com número real é menor que a faixa válidaEVariantError - Erro em operação com variantEZeroDivide - Divisão de real por zeroEDatabaseError - Erro genérico de banco de dados, geralmente não é usado diretamenteEDBEngineError - 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.

Page 8: Excessões TRY, EXCEPT, FINALLY

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.

Page 9: Excessões TRY, EXCEPT, FINALLY

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.

Page 10: Excessões TRY, EXCEPT, FINALLY

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

Page 11: Excessões TRY, EXCEPT, FINALLY

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.

Page 12: Excessões TRY, EXCEPT, FINALLY
Page 13: Excessões TRY, EXCEPT, FINALLY
Page 14: Excessões TRY, EXCEPT, FINALLY

5 - Nesse Exemplo, temos uma ocorrência parcialmente normal da Aplicação utilizando Try -> Try, Except, Finally -> Try, Excep t. O código na cláusula Try -> Tr y é executado por completo e em seguida, o código da clásula Finall y é executado entrando primeiro na clásula Tr y que está dentro de Finall y, 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 -> Tr y. Assim o código em Excep t é executado e após isso o restante do código do finall y é executado.

Page 15: Excessões TRY, EXCEPT, FINALLY

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

Page 16: Excessões TRY, EXCEPT, FINALLY

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.

Page 17: Excessões TRY, EXCEPT, FINALLY

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');

Page 18: Excessões TRY, EXCEPT, FINALLY

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