Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Programação Modular | Tratamento de Exceções

Programação Modular | Tratamento de Exceções

Slides utilizados em aula na disciplina Programação Modular do Instituto de Ciências Exatas e Informática - Sistemas de Informação. Pontifícia Universidade Católica de Minas Gerais - Unidade Barreiro, 1º Semestre 2015.

Eduardo Miranda

April 18, 2015
Tweet

More Decks by Eduardo Miranda

Other Decks in Education

Transcript

  1. Programação Modular Pontifícia Universidade Católica de Minas Gerais Unidade Barreiro

    — 1º Semestre 2015 Prof. Eduardo Miranda [email protected] Tratamento de Exceções
  2. Exceção Uma excepção é um evento que ocorre durante a

    execução de um programa e interrompe o fluxo normal de instruções do programa.
  3. Fonte: http://www.caelum.com.br/apostila-csharp-orientacao-objetos/excecoes/#16-1-retorno-do-metodo-para-controlar-erros Se tentarmos sacar um valor superior ao saldo

    do cliente, o método não permitirá o saque. Como notificar quem invocou o método que o saque foi feito com sucesso ou não? tratamento de exceções public class Conta { // Restante do código da classe public void saca(double valor) { if (valor <= this.saldo) { this.saldo -= valor; } }
  4. Uma primeira solução seria alterar o método Saca para retornar

    um booleano indicando se o saque foi ou não efetuado. Assim poderemos saber se o saque foi efetuado ao chamar o método. Fonte: http://www.caelum.com.br/apostila-csharp-orientacao-objetos/excecoes/#16-1-retorno-do-metodo-para-controlar-erros public class Conta { // Restante do código da classe public bool saca(double valor) { if (valor <= this.Saldo) { this.Saldo -= valor; return true; } else { return false; } } tratamento de exceções
  5. Contudo, uma desvantagem dessa abordagem é que, se esquecermos de

    testar o retorno do método Saca, podemos liberar dinheiro para o cliente sem permissão. E mesmo invocando o método e tratando o seu retorno de maneira adequada, o que faríamos se fosse necessário sinalizar exatamente qual foi o tipo de erro que aconteceu, como quando o usuário passou um valor negativo como quantidade? Fonte: http://www.caelum.com.br/apostila-csharp-orientacao-objetos/excecoes/#16-1-retorno-do-metodo-para-controlar-erros tratamento de exceções
  6. Uma solução seria alterar o retorno de boolean para número

    inteiro e retornar o código do erro que ocorreu. Isso é considerado uma má prática, pois o valor devolvido é "mágico" e só legível perante extensa documentação (magic numbers), além de não obrigar o programador a tratar esse retorno, o que pode levar o programa a continuar executando em um estado inconsistente. Fonte: http://www.caelum.com.br/apostila-csharp-orientacao-objetos/excecoes/#16-1-retorno-do-metodo-para-controlar-erros tratamento de exceções
  7. Para evitar este problemas, muitas linguagens de programação implementam mecanismos

    para o tratamento de exceções. O tratamento de exceções permite a criação de softwares que podem ligar com exceções em muitos casos, permitindo que um programa possa continuar a execução como se nenhum problema tivesse acontecido. O tratamento de exceções permite a criação de programas mais claros, robustos e tolerante a falhas. Ou seja, programas que são capazes de lidar com os problemas que possam surgir e continuar a execução. tratamento de exceções
  8. Fonte: http://www.caelum.com.br/apostila-csharp-orientacao-objetos/excecoes/#16-1-retorno-do-metodo-para-controlar-erros public class Conta { // Restante do código

    da classe public void saca(double valor) { if (valor > this.saldo) { throw new Exception("Valor do saque maior que o saldo"); } else { this.saldo -= valor; } } tratamento de exceções No nosso caso, utilizaremos a exceção Exception, indicando que houve um erro na operação de saque:
  9. Ao tentar fazer um saque maior que o saldo da

    conta seremos apresentados a seguinte mensagem de erro: tratamento de exceções
  10. Isso não resolve o problema porque nós estamos lançando uma

    exceção, um desvio da regra. Para evitar que o usuário veja esse tipo de erros, é preciso tratar as exceções. Isso é feito usando a instrução try-catch. Try-catch consiste em um bloco de try seguido por um ou mais cláusulas de catch , que especificam manipuladores para exceções diferentes. Quando uma exceção é lançada, o Common Language Runtime (CLR) procura a instrução catch que trata essa exceção. Se o método atualmente em execução não contiver um bloco catch, o CLR olha para o método que chamou o método atual, e assim por diante na pilha de chamadas. Não sencontrado nenhum bloco catch, o CLR exibe uma mensagem de exceção (exatamente como apresentado no último slide) sem tratamento para usuário e interrompe a execução do programa. tratamento de exceções
  11. public class ContaCorrente : Conta { public ContaCorrente(double saldo) :

    base(saldo) { } } static void Main(string[] args) { ContaCorrente cc = new ContaCorrente(100); try { cc.saca(150); Console.WriteLine("Saque realizado com sucesso."); } catch (Exception ex) { Console.WriteLine("Saldo insuficiente"); } } public class Conta { protected double saldo; public Conta(double s) { this.saldo = s; } public void saca(double valor) { if (valor > this.saldo) { throw new Exception("Valor do saque maior que o saldo"); } else { this.saldo -= valor; } } public double getSaldo() { return this.saldo; } } tratamento de exceções
  12. public class ContaCorrente : Conta { public ContaCorrente(double saldo) :

    base(saldo) { } } static void Main(string[] args) { ContaCorrente cc = new ContaCorrente(100); try { cc.saca(150); Console.WriteLine("Saque realizado com sucesso."); } catch (Exception ex) { Console.WriteLine("Saldo insuficiente"); } } public class Conta { protected double saldo; public Conta(double s) { this.saldo = s; } public void saca(double valor) { if (valor > this.saldo) { throw new Exception("Valor do saque maior que o saldo"); } else { this.saldo -= valor; } } public double getSaldo() { return this.saldo; } } tratamento de exceções Saída correta: Saldo insuficiente
  13. public class ContaCorrente : Conta { public ContaCorrente(double saldo) :

    base(saldo) { } } static void Main(string[] args) { ContaCorrente cc = new ContaCorrente(100); try { cc.saca(150); Console.WriteLine("Saque realizado com sucesso."); } catch (Exception ex) { Console.WriteLine("Saldo insuficiente"); } } public class Conta { protected double saldo; public Conta(double s) { this.saldo = s; } public void saca(double valor) { if (valor > this.saldo) { throw new Exception("Valor do saque maior que o saldo"); } else { this.saldo -= valor; } } public double getSaldo() { return this.saldo; } } tratamento de exceções O que acontece se o valor for um número negativo?
  14. public class ContaCorrente : Conta { public ContaCorrente(double saldo) :

    base(saldo) { } } static void Main(string[] args) { ContaCorrente cc = new ContaCorrente(100); try { cc.saca(150); Console.WriteLine("Saque realizado com sucesso."); } catch (Exception ex) { Console.WriteLine("Saldo insuficiente"); } } public class Conta { protected double saldo; public Conta(double s) { this.saldo = s; } public void saca(double valor) { if (valor > this.saldo) { throw new Exception("Valor do saque maior que o saldo"); } else { this.saldo -= valor; } } public double getSaldo() { return this.saldo; } } tratamento de exceções O que acontece se o valor for um número negativo? O código executa sem problemas! Mas a mensagem "Valor do saque maior que o saldo" não é adequada.
  15. Repare que, para lançarmos uma exceção, precisamos instanciar (comando new)

    um Exception. Ou seja, Exception é uma classe do C#! Podemos criar uma hierarquia de exceções utilizando a herança para indicar qual foi o tipo de erro que ocorreu. Para criarmos um novo tipo de exceção, precisamos apenas criar uma nova classe que herde de Exception. Vamos criar uma exceção que indica que ocorreu um erro por saldo insuficiente na conta, a SaldoInsuficienteException: Fonte: http://www.caelum.com.br/apostila-csharp-orientacao-objetos/excecoes/#16-1-retorno-do-metodo-para-controlar-erros tratamento de exceções public class SaldoInsuficienteException : Exception { }
  16. public class SaldoInsuficienteException : Exception { } public class Conta

    { // Restante do código da classe public void saca(double valor) { if (valor < 0) { throw new Exception(); } else if (valor > this.saldo) { throw new SaldoInsuficienteException(); } else { this.saldo -= valor; } } } tratamento de exceções
  17. public class SaldoInsuficienteException : Exception { } public class Conta

    { // Restante do código da classe public void saca(double valor) { if (valor < 0) { throw new Exception(); } else if (valor > this.saldo) { throw new SaldoInsuficienteException(); } else { this.saldo -= valor; } } } tratamento de exceções O C# já possui uma grande quantidade de exceções herdadas da classe System.Exception. Uma delas é chamada ArgumentException
  18. public class ContaCorrente : Conta { public ContaCorrente(double saldo) :

    base(saldo) { } } static void Main(string[] args) { ContaCorrente cc = new ContaCorrente(100); try { cc.saca(150); Console.WriteLine("Saque realizado com sucesso."); } catch (Exception ex) { Console.WriteLine(ex.Message); } } public class SaldoInsuficienteException : Exception { public SaldoInsuficienteException(String msg) : base(msg) { } } public class Conta { // Restante do código da classe public void saca(double valor) { if (valor < 0) { throw new ArgumentException("Valor de saque não permitido."); } else if (valor > this.saldo) { throw new SaldoInsuficienteException("Saldo insuficiente."); } else { this.saldo -= valor; } } } tratamento de exceções
  19. public class ContaCorrente : Conta { public ContaCorrente(double saldo) :

    base(saldo) { } } static void Main(string[] args) { ContaCorrente cc = new ContaCorrente(100); try { cc.saca(150); Console.WriteLine("Saque realizado com sucesso."); } catch (Exception ex) { Console.WriteLine(ex.Message); } } public class SaldoInsuficienteException : Exception { public SaldoInsuficienteException(String msg) : base(msg) { } } public class Conta { // Restante do código da classe public void saca(double valor) { if (valor < 0) { throw new ArgumentException("Valor de saque não permitido."); } else if (valor > this.saldo) { throw new SaldoInsuficienteException("Saldo insuficiente."); } else { this.saldo -= valor; } } } tratamento de exceções Mudança no construtor da classe
  20. public class ContaCorrente : Conta { public ContaCorrente(double saldo) :

    base(saldo) { } } static void Main(string[] args) { ContaCorrente cc = new ContaCorrente(100); try { cc.saca(150); Console.WriteLine("Saque realizado com sucesso."); } catch (Exception ex) { Console.WriteLine(ex.Message); } } public class SaldoInsuficienteException : Exception { public SaldoInsuficienteException(String msg) : base(msg) { } } public class Conta { // Restante do código da classe public void saca(double valor) { if (valor < 0) { throw new ArgumentException("Valor de saque não permitido."); } else if (valor > this.saldo) { throw new SaldoInsuficienteException("Saldo insuficiente."); } else { this.saldo -= valor; } } } tratamento de exceções Uso da exceção ArgumentException
  21. public class ContaCorrente : Conta { public ContaCorrente(double saldo) :

    base(saldo) { } } static void Main(string[] args) { ContaCorrente cc = new ContaCorrente(100); try { cc.saca(150); Console.WriteLine("Saque realizado com sucesso."); } catch (Exception ex) { Console.WriteLine(ex.Message); } } public class SaldoInsuficienteException : Exception { public SaldoInsuficienteException(String msg) : base(msg) { } } public class Conta { // Restante do código da classe public void saca(double valor) { if (valor < 0) { throw new ArgumentException("Valor de saque não permitido."); } else if (valor > this.saldo) { throw new SaldoInsuficienteException("Saldo insuficiente."); } else { this.saldo -= valor; } } } tratamento de exceções Uso da mensagem enviada pela exceção
  22. public class ContaCorrente : Conta { public ContaCorrente(double saldo) :

    base(saldo) { } } static void Main(string[] args) { ContaCorrente cc = new ContaCorrente(100); try { cc.saca(150); Console.WriteLine("Saque realizado com sucesso."); } catch (Exception ex) { Console.WriteLine(ex.Message); } } public class SaldoInsuficienteException : Exception { public SaldoInsuficienteException(String msg) : base(msg) { } } public class Conta { // Restante do código da classe public void saca(double valor) { if (valor < 0) { throw new ArgumentException("Valor de saque não permitido."); } else if (valor > this.saldo) { throw new SaldoInsuficienteException("Saldo insuficiente."); } else { this.saldo -= valor; } } } tratamento de exceções Saída correta: Saldo insuficiente.
  23. public class ContaCorrente : Conta { public ContaCorrente(double saldo) :

    base(saldo) { } } static void Main(string[] args) { ContaCorrente cc = new ContaCorrente(100); try { cc.saca( -150 ); Console.WriteLine("Saque realizado com sucesso."); } catch (Exception ex) { Console.WriteLine(ex.Message); } } public class SaldoInsuficienteException : Exception { public SaldoInsuficienteException(String msg) : base(msg) { } } public class Conta { // Restante do código da classe public void saca(double valor) { if (valor < 0) { throw new ArgumentException("Valor de saque não permitido."); } else if (valor > this.saldo) { throw new SaldoInsuficienteException("Saldo insuficiente."); } else { this.saldo -= valor; } } } tratamento de exceções Saída correta: Valor de saque não permitido.
  24. Quais das opções a seguir representa o lançamento de uma

    nova exceção em nosso sistema? Fonte: http://www.caelum.com.br/apostila-csharp-orientacao-objetos/excecoes/#16-1-retorno-do-metodo-para-controlar-erros exercícios throw new Exception(); return Exception(); return new Exception(); throw Exception();
  25. Quais das opções a seguir representa o lançamento de uma

    nova exceção em nosso sistema? Fonte: http://www.caelum.com.br/apostila-csharp-orientacao-objetos/excecoes/#16-1-retorno-do-metodo-para-controlar-erros exercícios throw new Exception(); return Exception(); return new Exception(); throw Exception();
  26. Analise o código a seguir e assinale a alternativa correta:

    Fonte: http://www.caelum.com.br/apostila-csharp-orientacao-objetos/excecoes/#16-1-retorno-do-metodo-para-controlar-erros exercícios var conta = new Conta(); var caixa = new Caixa(); conta.Deposita(100.0); conta.Saca(500.0); caixa.Libera(500.0); A. Se a linha 4 lançar uma exceção, a linha 5 não será executada. B. A última linha não será executada mesmo se o código não lançar exceções. C. Se a linha 4 lançar uma exceção, nenhuma das linhas será executada. D. Todas as linhas são executadas mesmo quando alguma delas lança uma exceção.
  27. Analise o código a seguir e assinale a alternativa correta:

    Fonte: http://www.caelum.com.br/apostila-csharp-orientacao-objetos/excecoes/#16-1-retorno-do-metodo-para-controlar-erros exercícios var conta = new Conta(); var caixa = new Caixa(); conta.Deposita(100.0); conta.Saca(500.0); caixa.Libera(500.0); A. Se a linha 4 lançar uma exceção, a linha 5 não será executada. B. A última linha não será executada mesmo se o código não lançar exceções. C. Se a linha 4 lançar uma exceção, nenhuma das linhas será executada. D. Todas as linhas são executadas mesmo quando alguma delas lança uma exceção.
  28. Onde devemos colocar um trecho de código que pode lançar

    uma exceção para quando queremos tratá-la? A. Dentro de um bloco try B. Dentro de um bloco catch C. Não precisa estar em nenhum bloco em específico. Onde devemos colocar o código que trata uma exceção? A. Dentro de um bloco catch B. Dentro de um bloco try C. Não precisa estar em nenhum bloco em específico. Fonte: http://www.caelum.com.br/apostila-csharp-orientacao-objetos/excecoes/#16-1-retorno-do-metodo-para-controlar-erros exercícios
  29. Fonte: http://www.caelum.com.br/apostila-csharp-orientacao-objetos/excecoes/#16-1-retorno-do-metodo-para-controlar-erros exercícios Onde devemos colocar um trecho de código

    que pode lançar uma exceção para quando queremos tratá-la? A. Dentro de um bloco try B. Dentro de um bloco catch C. Não precisa estar em nenhum bloco em específico. Onde devemos colocar o código que trata uma exceção? D. Dentro de um bloco catch A. Dentro de um bloco try B. Não precisa estar em nenhum bloco em específico.
  30. O C# já possui implementado a classe List<T> e um

    dos vários métodos implementados se chama Insert. A assinatira do método Insert é a seguinte: exercícios Implemente o método Insert para que ele lance a exceção ArgumentOutOfRangeException – também existente no C# – quando: • index é menor que 0; • ou quando index é maior que o tamanho atual da lista. Observação. A classe List já possui o atributo Count que armazena o tamanho atual da lista. public void Insert( int index, T item )
  31. vantagens do uso de exceções Programas freqüentemente solicitam e liberam

    recursos de forma dinâmica – em tempo de execução. Por exemplo, um programa que lê um arquivo do disco faz um pedido de abertura de arquivo. Se esse pedido for bem-sucedido, o programa lê o conteúdo do arquivo. Os sistemas operacionais geralmente impedem que mais do um programa manipule o mesmo arquivo simultaneamente. Portanto, quando um programa terminar o processamento de um arquivo, ele deve fechar o arquivo (ou seja, liberar o recurso para que outros (resource leak). Nesse caso, o recurso – arquivo – estará disponível para outros programas.
  32. vantagens do uso de exceções Em linguagens de programação como

    C e C ++, no qual o programador é responsável pelo gerenciamento de memória dinâmica, o tipo mais comum de vazamento de recursos é o vazamento de memória (memory leak) . Um vazamento de memória ocorre quando um programa aloca memória (em C# isso é feito através de palavra-chave new), mas não desalocar a memória, quando ela não é mais necessário. Normalmente, isso não é um problema em C#, porque o CLR executa a coleta de lixo de memória que não é mais necessária para um programa em execução. No entanto, outros tipos de vazamentos de recursos (como arquivos não fechados) podem ocorrer.
  33. destruiores Todo objeto tem um membro especial, chamado de destruidor,

    que é chamado pelo coletor de lixo para executar o serviço de limpeza de um objeto. O destruidor é declarado como um construtor sem parâmetros, exceto que seu nome é o nome da classe, precedido por um til (~). class Car { ~Car() // destruidor { // desalocação dos recursos } }
  34. destruidores • Destruidores não podem ser definidas em estruturas (structs).

    Eles são usados somente com classes. • Uma classe só pode ter um destruidor. • Destruidores não podem ser herdadas ou sobrecarregados. • Destruidores não podem ser chamados. Eles são invocados automaticamente. • Um destruidor não leva modificadores nem tem parâmetros. O programador não tem controle sobre quando o destruidor é chamado porque isso é determinado pelo coletor de lixo. Se um objeto é considerado elegível para destruição, ele chama o destruidor (se houver) e recupera a memória usada para armazenar o objeto. Destruidores também são chamados quando o programa é encerrado.
  35. class Third : Second { ~Third() { System.Diagnostics.Trace.WriteLine("Terceiro destrutor sendo

    chamado."); } } class TestDestructors { static void Main() { Third t = new Third(); } } class First { ~First() { System.Diagnostics.Trace.WriteLine("Primeiro destrutor sendo chamado."); } } class Second : First { ~Second() { System.Diagnostics.Trace.WriteLine("Segundo destrutor sendo chamado."); } } tratamento de exceções
  36. class Third : Second { ~Third() { System.Diagnostics.Trace.WriteLine("Terceiro destrutor sendo

    chamado."); } } class TestDestructors { static void Main() { Third t = new Third(); } } class First { ~First() { System.Diagnostics.Trace.WriteLine("Primeiro destrutor sendo chamado."); } } class Second : First { ~Second() { System.Diagnostics.Trace.WriteLine("Segundo destrutor sendo chamado."); } } tratamento de exceções Saída correta: Terceiro destrutor sendo chamado. Segundo destrutor sendo chamado. Primeiro destrutor sendo chamado.
  37. bloco finally O C# prevê um bloco chamado finally, que

    é garantido ser executar independentemente de ter havido alguma exceção no bloco try. Isso faz do bloco finally o local ideal no para colocar o código de liberação de recursos para os recursos que são adquiridos e manipulados no correspondente bloco try. Colocando código de limpeza em um bloco finally é sempre uma boa prática, mesmo quando não há exceções esperadas.
  38. using System; namespace ExceptionClass { class Program { static void

    Main(string[] args) { try { Console.WriteLine("A"); throw new Exception(); Console.WriteLine("B"); } catch (Exception e) { Console.WriteLine("C"); } finally { Console.WriteLine("D"); } } } } bloco finally
  39. using System; namespace ExceptionClass { class Program { static void

    Main(string[] args) { try { Console.WriteLine("A"); throw new Exception(); Console.WriteLine("B"); } catch (Exception e) { Console.WriteLine("C"); } finally { Console.WriteLine("D"); } } } } Saída correta: A C D bloco finally
  40. E exemplo abaixo em C# lê um arquivo, linha por

    linha, e imprime no prompt o conteúdo lido. Melhore o código abaixo usando o tratamento de exceções. exercícios using System; using System.IO; class Program { static void Main() { string line; System.IO.StreamReader file = new System.IO.StreamReader("C:\\test.txt"); while ((line = file.ReadLine()) != null) { Console.WriteLine(line); } file.Close(); } } Possíveis exceções: • DirectoryNotFoundException • EndOfStreamException • FileNotFoundException • FileLoadException • PathTooLongException
  41. referência APOSTILA C# E ORIENTAÇÃO A OBJETOS – Caelum, Capítulo

    16 http://www.caelum.com.br/apostila-csharp-orientacao-objetos/excecoes/#16-1-retorno-do-metodo-para-controlar-erros Paul Deitel, Harvey Deitel. Visual C# 2012 How to Program (5th Edition) – Capítulo 13. Prentice Hall (2013), 1024 páginas try-catch (C# Reference). Acesso em 12 de Abril de 2015. https://msdn.microsoft.com/en-us/library/0yd65esw.aspx Destruidores (Guia de Programação em C#). Acesso em 17 de Abril de 2015. https://msdn.microsoft.com/pt-br/library/66x5fx1b.aspx The Java™ Tutorials - Lesson: Exceptions. Acesso em 17 de Abril de 2015 https://docs.oracle.com/javase/tutorial/essential/exceptions/