Baixe o app para aproveitar ainda mais
Prévia do material em texto
AULA 13 - CCT0024 – Linguagem de Programação Objetivos Recordando... Na aula passada, vimos como criar interfaces gráficas e tratar eventos gerados pelo teclado e mouse. Hoje veremos como tratar as possíveis exceções geradas a partir da execução comandos do próprio programa, quer por operações erradas acusadas pelo sistema operacional quer por métodos das bibliotecas disponibilizadas que não puderam realizar as tarefas requisitadas. Também aprenderemos como gerar exceções proprietárias oriundas da quebra de regras de negócio da aplicação. Conceito de exceção Uma exceção é uma indicação de um problema que ocorre durante a execução de um programa. O tratamento da exceção permite que programadores gerem aplicativos que possam resolver situações em que exceções acorram, objetivando a continuidade na execução, garantindo aos aplicativos características de robustez e tolerância a falhas. Vejamos o que ocorre em um aplicativo que não utiliza tratamento de exceção. A classe a seguir solicita do usuário dois inteiros e calcula seu quociente. Neste caso, podemos verificar que as exceções são lançadas (ocorrem) quando um problema é detectado e não há como tratá-lo. Compreender o conceito de exceção Aprender a tratar exceções nos programas Entender a hierarquia das exceções Criar e lançar uma exceção proprietária import java.util.Scanner; public class GeraErro{// demonstra exceção de div. por zero public static int dividir(int numerador,int denominador){ return numerador / denominador; // possivel erro } public static void main(String args[]){ Scanner scanner = new Scanner( System.in ); System.out.print( "Entre com numerador inteiro: " ); int numerador = scanner.nextInt(); System.out.print( "Entre com denominador inteiro: " ); int denominador = scanner.nextInt(); int resultado = dividir (numerador, denominador); System.out.printf("\n %d / %d = %d\n", numerador, denominador, resultado); } // fim do main } Se executarmos o aplicativo anterior e digitarmos dois números inteiros, sendo o segundo diferente de zero, o aplicativo executará normalmente informando o inteiro resultando da divisão dos dois números. Se em uma execução digitarmos para denominador o valor zero, ocorre erro e várias linhas, conhecidas como rastreamento de pilha, são apresentadas. Neste caso, como não é possível dividir por zero, a exceção ArithmeticException do pacote java.lang é lançada e uma informação extra “/ by zero” fornece detalhes sobre a exceção específica. Se, em outra execução, digitarmos um caractere não numérico, é gerada uma ocorrência de InputMismatchException do pacote java.util. Note que nas linhas rastreamento de pilha, há informação da linha de código em que a exceção é detectada. Tratamento das exceções Reescrevemos o aplicativo anterior utilizando tratamento de exceções para processar as ArithmeticExceptions e InputMismatchExceptions. A classe agora trata as exceções de forma que, se o usuário cometer um erro, o programa captura e trata as exceções, permitindo a re-inserção dos dados. import java.util.InputMismatchException; import java.util.Scanner; public class TrataErro{ // demonstra o lançamento de exceções public static int dividir(int numerador, int denominador) throws ArithmeticException{ return numerador / denominador; //possivel erro } // fim de método quotiente public static void main( String args[] ) { Scanner ent = new Scanner(System.in); // determina se mais entradas são necessarias boolean continueLoop = true; do { try { System.out.print("Entre c/ numerador: " ); int numerador = ent.nextInt(); System.out.print("Entre c/ denominador: "); int denominador = ent.nextInt(); int resultado = dividir(numerador, denominador); System.out.printf("\n%d / %d = %d\n", numerador, denominador, resultado ); continueLoop = false; // entrada ok; fim de loop } // fim de try catch(InputMismatchException inputMismatchException){ System.err.printf( "\nExceção : %s\n", inputMismatchException ); // descarta entrada para nova tentativa ent.nextLine(); System.out.println("Entre com inteiros.\n"); } // fim de catch catch (ArithmeticException arithmeticException){ System.err.printf("\nExceção: %s\n", arithmeticException); System.out.println("Divisão por zero.” + "Tente novamente.\n" ); } // fim de catch } while (continueLoop); // fim de do/while } // fim do main } A classe acima contém um bloco try que inclui o código que pode “lançar” uma exceção, deixando claro que ao ocorrer uma exceção, o restante do código a partir na instrução que ocasionou a exceção não é executado. A instrução try consiste na palavra chave try seguida por um bloco de código entre chaves “{}”, e normalmente nos referirmos como bloco try ao(s) comando(s) dentro da chaves da instrução try. O bloco try é seguido por dois blocos catch, um que trata uma InputMismatchException e outro que trata uma ArithmeticException. Um bloco catch, também chamado de cláusula catch ou handler de exceção, captura e trata a exceção. Um bloco catch inicia-se com a palavra-chave catch e é seguido por um parâmetro entre parênteses (parâmetro de exceção) e um bloco de código entre chaves. Da mesma forma, é comum utilizarmos o termo bloco catch para designar o código entre as chaves. Pelo menos um bloco catch ou um bloco finally deve se seguir imediatamente ao bloco try. Todo bloco catch especifica um parâmetro de exceção entre parênteses que identifica o tipo de exceção que o handler pode processar. Quando uma exceção ocorre em um bloco try, o bloco catch que é executado é aquele que corresponde exatamente ao tipo da exceção que ocorreu ou a uma superclasse dela. O nome do parâmetro de exceção permite ao bloco catch utilizar o objeto de exceção, como por exemplo, chamar implicitamente o método toString da exceção capturada para exibir informações básicas sobre a exceção. Os programadores Java costumam utilizar simplesmente a letra e como o nome de parâmetros de exceção. Utilizando a cláusula throws Na aplicação anterior, especificamente na declaração do método dividir utiliza-se a cláusula throws. Esta declaração especifica que o método pode lançar uma exceção em caso de erro. A referida cláusula, sintaticamente, pode aparecer após a lista de parâmetros do método e conter uma lista de exceções separadas por vírgulas que o método lançará se ocorrer um problema. Essas exceções podem ser lançadas por instruções no corpo de método ou por métodos chamados no corpo. Um método pode lançar exceções das classes listadas em sua cláusula throws ou de suas subclasses. No caso da classe TrataErro, os clientes do método dividir() são informados que o método pode lançar uma ArithmeticException. Todas as classes de exceção do Java herdam, direta ou indiretamente, da classe Exception, formando uma hierarquia de herança que pode ser estendida pelos programadores para formar sua própria classe de exceção. Várias classes de exceçãopodem ser derivadas de uma superclasse comum. Se um handler catch for escrito para capturar objetos de exceção de um tipo de superclasse, ele também pode capturar todos os objetos de subclasses dessa classe. Se houver múltiplos blocos catch que correspondem a um tipo particular de exceção, somente o primeiro bloco catch correspondente executará na ocorrência da exceção desse tipo. Se seguirmos a um bloco try, com um bloco catch para o tipo AtithmeticException e outro catch para o tipo Exception, somente o primeiro bloco correspondente executaria. O Bloco Finally Os programas que obtêm certos recursos do ambiente operacional devem retorna- los para evitar os supostos vazamentos de recursos. O tipo mais comum é o vazamento de memória. O Java realiza a coleta automática de lixo de memória não mais utilizada por programas, evitando assim a maioria dos vazamentos de memória. Entretanto outros tipos de vazamentos podem ocorrer, como por exemplo, arquivos, conexões com bancos de dados, com redes que não são fechadas adequadamente e que talvez não fiquem disponíveis para uso em outros aplicativos. O bloco finally, que também é composto de chaves, é opcional. Se estiver presente, este bloco é colocado depois do último bloco catch como mostrado a seguir. O Java garante que o bloco finally caso esteja presente, executará se uma exceção for lançada no bloco try correspondente ou quaisquer de seus blocos catch. Também executará se um bloco try fechar utilizando a instrução return, break ou continue. Entretanto não executará se o aplicativo fechar antes de um bloco try chamando o método System.exit que encerra imediatamente o aplicativo. try{ } catch (TipoExceção1 exceção1){ } catch (TipoExceção2 exceção2){ } finally{ << instruções de liberação de recursos >> } Lançando a exceção em tratamentos aninhados Se uma exceção que ocorre em um bloco try não puder ser capturada por handlers catch desse bloco try, o aplicativo pula o restante do bloco try e prossegue para o bloco finally. Então o programa passa a exceção para o próximo bloco try externo caso haja, normalmente no método chamador, onde um bloco catch pode capturá-la. A classe a seguir mostra que o bloco finally ainda executará mesmo que não seja lançada uma exceção no bloco try correspondente. public class UsandoExceptions { public static void main( String args[] ) { try { lancaExcecao(); // chama método throwException } // exceção lançada por throwException catch ( Exception e ) { System.err.println( "Exceção tratada no main" ); System.out.printf( "Exceção : %s\n", e ); } naolancaExcecao(); } // fim de main public static void lancaExcecao() throws Exception{ try { // lança uma exceção System.out.println( "Método lancaExcecao" ); throw new Exception(); // gera a exceção } // captura exceção lançada em try catch ( Exception e ) { System.err.println( "Exceção tratada no método lancaExcecao" ); System.out.printf( "Exceção : %s\n", e ); throw e; // Lança novamente a exceção para // processamento adicional no main } // fim de catch finally { // executa quer ocorra ou não a exceção System.err.println("Finally em lancaExcecao" ); } // fim de finally } public static void naolancaExcecao() { try { // bloco try não lança uma exceção System.out.println( "Método naolancaExcecao" ); } // fim de try catch ( Exception e ) { // não executa System.err.println( e ); } // fim de catch finally { // executa independentemente do que ocorre // em try...catch System.err.println( "Finally executado em naolancaExcecao" ); } // fim de finally System.out.println( "Fim de naolancaExcecao" ); } } A instrução no método lancaExcecao() throw new Exception(); é conhecida como instrução throw e é executada para forçar a geração de uma exceção. Como está dentro de um try, ocorrerá o desvio para o catch.. A instrução no método lancaExcecao() throw e; relança a exceção. Os programadores podem relançar exceções, utilizando essa instrução, para indicar ao método cliente que ocorreu um erro. Exceções são relançadas quando um bloco catch não pode processar uma exceção, ou só pode acessá-la parcialmente. Relançar uma exceção adia o tratamento de exceção para outro bloco catch associado com uma instrução try externa. Uma exceção é relançada utilizando a palavra-chave throw, seguida por uma referência ao objeto de exceção que acabou de ser capturado. Um exceção não pode ser relançada de um bloco finally. No método naolancaExcecao() nenhuma exceção é lançada no bloco try, então o programa “pula” o bloco catch. Apesar disto, o bloco finally é executado. Desafio 1. Analise o código a seguir: import javax.swing.*; import java.awt.*; public class TelaMensagem extends JFrame { private JButton btnExibir; private JTextField txtExibir; public TelaMensagem() { txtExibir = new JTextField(); btnExibir = new JButton(); getContentPane().setLayout( new FlowLayout()); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setResizable(false); txtExibir.setColumns(40); getContentPane().add(txtExibir); btnExibir.setText("Exibir"); getContentPane().add(btnExibir); pack(); } public static void main( String[] args ){ new TelaMensagem().setVisible(true); } Utilizando a linguagem Java escreva o código que adicione um evento para o botão responsável por exibir na tela o valor digitado na caixa de texto. Se o valor digitado não for numérico, a exceção deve ser tratada e uma mensagem deve ser passada ao usuário. O valor numérico deve ser positivo. Se esta condição não for atendida, o sistema deve gerar uma exceção proprietária e esta deve ser tratada em um nível superior. 2) Queremos fazer uma calculadora de quatro operações com botões para os operadores e caixas de texto para os operandos. A aparência da interface gráfica deve ser a seguinte: Nas caixas de texto mais à esquerda devem ser digitados os operandos reais da operação a ser realizada. Após a digitação dos operandos, o operador deve clicar em um dos botões de operadores e o número real correspondente ao resultado deve ser exibido na caixa de texto mais à direita. A aplicação deve emitir avisos caso o valor digitado não seja um número ou caso seja solicitada uma divisão por zero.
Compartilhar