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.
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; } }
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
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
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
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
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:
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
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?
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.
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 { }
{ // 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
{ // 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
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
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
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
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
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.
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.
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();
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();
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.
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.
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
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.
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 )
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.
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.
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 } }
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.
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
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.
é 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.
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
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/