• Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,011
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
40
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Curso de Java – Módulo I Exceções, Entrada e Saída Programação Swing Fábio Mengue – fabio@unicamp.br Centro de Computação - Unicamp Exceções O termo exception é uma abreviatura da frase “exceptional event”. Sua definição formal éum evento que ocorre durante a execução de um programa que quebra o fluxo normal dessaexecução. Vários eventos podem causar exceções. Desde problemas sérios com hardware (como umcrash de disco) até um erro simples de programação, como acessar um elemento de um vetorcom um índice inválido. Quando um erro desses tipos ocorrem em um método Java, o métodocria um objeto do tipo Exception e o envia para o sistema. Esse objeto contém informação sobreo erro, incluindo seu tipo e o estado em que o programa se encontrava quando o erro aconteceu.O sistema fica responsável por encontrar alguma maneira de lidar corretamente com o erro. Nalinguagem usada pelos programadores Java, dizemos que o sistema gerou uma exceção (eminglês, throwed an exception). Depois que o método gerou uma exceção, o sistema tenta encontrar algum código quepossa ser utilizado para lidar com a exceção. Os candidatos mais prováveis são os que“chamaram” o método onde o erro aconteceu. Se eles não tiverem condições de lidar com oerro, o sistema continua a seguir a pilha de chamadas, até encontrar o código apropriado. Por suavez, o código é considerado apropriado para lidar com uma exceção quando o tipo da exceçãogerada é o mesmo tipo para o qual ele foi programado. Ao ser encontrado o código correto, osistema o executa (em inglês, catch the exception). Caso o sistema não consiga identificar um código correto para gerenciar a exceção, osistema (normalmente representado pelo programa Java) se encerra. Claro que é desnecessáriodizer que isso não é exatamente o que gostaríamos que acontecesse na maioria das vezes. Pelo fato de utilizar exceções para gerenciar erros, os programas em java possuemvantagens sobre as linguagens tradicionais. A primeira grande vangatem é poder separar ogerenciamento de erros do código comum. Outra vantagem é a propagação de erros, que permiteque se crie uma classe especializada apenas no gerenciamento destes eventos. E por fim, épossível agrupar erros por tipo, tratando-os de uma vez. Veremos exemplos para cada uma dasvantagens a seguir.1
  • 2. Nas linguagens de programação tradicionais, a detecção de erros e seu tratamentonormalmente causa uma certa confusão no código, pois tudo está misturado. Por exemplo,imagine que você tenha uma função que leia um arquivo do disco para a memória. Imagine queesse programa se parece com isso:lerArquivo{ abrir o arquivo; determinar seu tamanho; alocar memória; ler o arquivo para a memória; fechar o arquivo;} Parece muito simples. Mas o que acontece se:  O arquivo não puder ser aberto ?  For impossível determinar o tamanho do arquivo ?  Não for possível alocar a quantidade total de memória ?  A leitura falhar ?  O arquivo não puder ser fechado ? Então, criamos código a mais para detectar e lidar com esses possíveis erros. Assim,nosso programa agora ficaria assim:lerArquivo { codigoErro=0; abrir arquivo; if (arquivoAberto) { determinar tamanho; if (tamanhoDeterminado) { alocar memória; if (memoriaAlocada) { ler o arquivo para a memória; if (leituraFalhou) { codigoErro=-1; } else { codigoErro=-2; } } else { codigoErro=-3; } fechar arquivo; if (arquivoNaoFechado) && codigoErro=0) { codigoErro=-4; }2
  • 3. }} Desta maneira, seu programa com 7 linhas ficou praticamente 3 vezes maior. O pior éque o código a mais torna o programa um tanto ilegível, e a lógica se perde no meio dos ifs eelses, dificultando a identificação de quais pedaços do código estão realmente fazendo parte dalinha de raciocínio deste programa. Depois de algumas manutenções, o código deve ficar aindapior de ler, e os programadores geralmente irão resolver o problema simplesmente ignorando aprevenção aos erros; eles irão aparecer quando o programa “der pau”. A soluçaõ encontrada pelo Java é mais elegante. O programador irá escrever o programade maneira usual, mas o tratamento de erros estará separado. Se sua função for reescrita àmaneira Java, ficaria assim:lerArquivo { try { abrir arquivo; determinar tamanho; alocar memória; ler o arquivo para memória; fechar arquivo; } catch (falhaAberturaArquivo) { Código de tratamento } } catch (falhaDeterminarTamanho) { Código de tratamento } } catch (falhaAlocacaoMemoria) { Código de tratamento } } catch (falhaLeitura) { Código de tratamento } } catch (falhaFechamentoArquivo) { Código de tratamento }} Note que o trabalho de criar código para gerenciar o erro continua. O que temos é aseparação dos detalhes do que fazer quando algo acontece. O Java automaticamente executaapenas o código que se relaciona com o erro, tornando desnecessária a construção de cadeias if-else para gerenciar os erros. O programa também fica maior, mas mais legivel e ainda sim menordo que na abordagem tradicional. A segunda vantagem que existe na utilização de exceções é a habilidade de propagarerros. Suponha que nossa função lerArquivo é o quarto método em uma série de métodos3
  • 4. implementados em sua classe. O metodo1 chama o metodo2, que chama metodo3, quefinalmente chama lerArquivo.metodo1 { call method2;}metodo2 { call method3;}metodo3 { call lerArquivo;} Suponha que o código em metodo1 seja o único interessado nos erros que podemacontecer em lerArquivo. Se isso fosse ser implementado usando a notificação tradicional,metodo3 e metodo2 deveriam ter maneiras de propagar códigos de erro eventualmenteretornados por lerArquivo para os métodos que os invocaram, até chegar a metodo1.metodo1 { errorCodeType error; error = call metodo2; if (error) doErrorProcessing; else proceed;}errorCodeType metodo2 { errorCodeType error; error = call metodo3; if (error) return error; else proceed;}errorCodeType metodo3 { errorCodeType error; error = call lerArquivo; if (error) return error; else proceed;}4
  • 5. Como já visto, o sistema Java irá procurar automaticamente um código adequado para ogerenciamento de erros. Usamos então uma palavra que indica que qualquer exceção ocorrida (enão tratada) deve ter propagada para a classe que “chamou” a classe corrente. Veja o exemplo:metodo1 { try { call metodo2; } catch (Exception) { doErrorProcessing; }}metodo2 throws Exception { call metodo3;}metodo3 throws Exception { call lerArquivo;} Entretanto, como pode ser visto no código, o envio das exceções exige um certo esforçodos métodos intermediários, que também necessitam repassar a exceção com throws até ométodo correto. Mesmo assim, essa técnica obviamente é mais vantajosa que a tradicional, nosentido que evita confusão no código. A última mas não menos importante vantagem é que as exceções são agrupadas. Porexemplo, imagine um grupo de exceções. Todas elas dizem respeito a erros que podem ocorrerquando se manipula um vetor. Exceção para estouro do vetor, para inclusão de tipo inválido, oumesmo para quando o elemento procurado não faz parte do vetor. Cada uma dessas exceçõespode ser tratada de maneira independente, ou você pode ter um método que trate todas asexceções deste grupo, tornando a coisa mais simples. Pelo fato das exceções serem classes Java como qualquer outra, a hierarquia presente emtodas as classes Java também está presente aqui. Todas elas são instâncias ou descendentes daclasse Throwable. Cada “folha” da árvore que se inicia em Throwable representa uma exceçãoespecífica, e cada “tronco” representa um grupo relacionado de exceções. Por exemplo, ArrayException é uma subclasse de Exception (por sua vez, uma subclassede Throwable), e possui 3 subclasses: InvalidIndexException, ElementTypeException,NoSuchElementException. Cada uma delas representa um erro específico, que pode ocorrer namanipulação de um vetor. Uma maneira de lidar com as exceções é uma a uma:catch (InvalidIndexException e) { ...} Outra maneira seria tratando a exceção de acordo com o grupo ao qual ela pertence. Issopode ser feito por vários motivos, o mais forte deles é manter a simpliciadade. No nossoexemplo, temos ArrayException, que representa qualquer erro que pode acontecer com a5
  • 6. manipulação de um vetor. Assim, um método pode lidar com uma exceção baseada em suahierarquia. Por exemplo:catch (ArrayException e) { ...} Este método lida com todas as exceções que dizem respeito a vetores. É possível saberqual a exceção através de uma pergunta ao objeto e, recebido como parâmetro. Também épossível definir um método que lida com qualquer exceção que chegar até ele, como no exemplo:catch (Exception e) { ...}Seu primeiro encontro com exceções Java. Veja a mensagem de erro abaixo. Ela é gerada pois a classe que estamos compilandocontém chamadas a métodos que lançam exceções quando um erro acontece. InputFile.java:8: Warning: Exception java.io.FileNotFoundException must be caught, or it must be declared in throws clause of this method. in = new FileReader(filename); ^ A linguagem Java exige que os métodos capturem ou especifiquem o lançamento deexceções que podem acontecer dentro daquele escopo. Se o compilador identifica que aquelepedaço de código não possui código adequado para o tratamento de exceções, a mensagem deerro acima é apresentada e o programa simplesmente não é compilado. Vamos ver o código do programa InputFile.java e verificar a causa do erro. import java.io.*; public class InputFile { private FileReader in; public InputFile(String filename) { in = new FileReader(filename); } public String getWord() { int c; StringBuffer buf = new StringBuffer();6
  • 7. do { c = in.read(); if (Character.isWhitespace((char)c)) return buf.toString(); else buf.append((char)c); } while (c != -1); return buf.toString(); } } O compilador apresenta o erro na linha 8 (in = new FileReader(filename);). Essainstrução cria um objeto FileReader, usado para abrir um arquivo cujo nome é passado comoparâmetro. O que acontece se o arquivo não existir no disco ? Os profissionais que desenharam aclasse FileReader não tinham a menor idéia do que o programador gostaria que acontecesse casoo arquivo não existisse. O programa deve terminar ? Um nome de arquivo diferente deve sertestado ? O arquivo deve ser criado ? Não existe jeito de saber o que o programador que estáutilizando o FileReader gostaria que acontecesse nessa situação. Assim, eles geram uma exceção(do tipo java.io.FileNotFoundException). Assim, o método que chamou a instrução decide amaneira apropriada de tratar do assunto. No nosso exemplo, pode se ver que o programa ignora o fato de que FileReader podegerar uma exceção. Mas o compilador Java não deixa que o fato passe em branco, se recusando acompilar o programa e gerando uma mensagem de erro que alerta o programador a respeito. Além da mensagem vista acima, outra mensagem deve ser gerada: InputFile.java:15: Warning: Exception java.io.IOException must be caught, or it must be declared in throws clause of this method. while ((c = in.read()) != -1) { ^ Agora, o problema está no objeto in, que da classe FileReader. O método read() tambémpode gerar uma exceção, desta vez caso algum problema aconteça na leitura. Por exemplo, se aspermissões do arquivo não estejam configuradas de modo que esse programa possa ler seusdados. A exceção gerada pode esse método é java.io.IOException. Nesse ponto, você tem duas opções. Ou pode criar o código para capturar as exceçõesdentro do programa InputFile ou propaga-las para outros métodos mais acima na pilha deexecução. De qualquer maneira, o programa InputFile deve fazer alguma coisa. E para fazer issoexiste uma maneira correta.7
  • 8. O Bloco try O primeiro passo para construir um programa capaz de gerenciar exceções é colocar oscomandos que podem gerar exceções dentro de um mesmo contexto, usando a palavra reservadatry: try { Comandos... } Você pode colocar cada um dos comandos em um contexto próprio, ou pode colocartodos os comandos que podem gerar exceção em apenas um contexto e depois programar(separadamente) o código que irá lidar com cada uma das exceções. Por exemplo: PrintWriter out = null; try { out = new PrintWriter( new FileWriter("OutFile.txt")); for (int i = 0; i < size; i++) out.println("Value at: " + i + " = " + victor.elementAt(i)); } O bloco try neste programa delimita o escopo sobre o qual o código de tratamento deerros irá atuar. Nesse pedaço de código existem duas instruções que podem gerar exceções; vocêconsegue identifica-las ? Uma instrução try deve ser acompanha de pelo menos um bloco catch.O Bloco catch A instrução catch define qual o código que irá ser executado, dependendo da exceçãogerada. Você os associa aos blocos definidos pelo try colocando-os logo após o bloco: try { ... } catch ( . . . ) { ... } catch ( . . . ) { ... }... Não se deve ter nenhuma outra instrução entre o final do contexto do try e o início docatch.8
  • 9. A forma geral do catch é: catch (SomeThrowableObject variavel) { Comandos... } Note que ele é muito parecido com um método. Todo bloco catch identifica o tipo deexceção que ele trata (SomeThrowableObjet, que é o nome da classe-filho de Throwable) erecebe como parâmetro a exceção recebida. Essa exceção, como tudo em Java, é um objeto. Sendo subclasse de Throwable, esseobjeto herda uma série de métdos. Um dos mais utilizados é o getMessage(), que serve paramostrar qual a mensagem de erro. Temos ainda métodos para mostrar a pilha de execução e vocêpode definir ainda suas próprias exceções (basta criar uma classe que extends Throwable). O bloco catch contém normalmente comandos comuns do Java. Muitas vezes o blocoserve simplesmente para imprimir uma mensagem indicando o erro e parando o programa. Obloco é executado apenas se a exceção for disparada; os outros blocos catch são ignorados. Se utilizarmos como exemplo o código apresentado na página anterior, podemos definiros blocos catch da maneira mostrada abaixo: try { ... } catch (ArrayIndexOutOfBoundsException e) { System.err.println("Caught ArrayIndexOutOfBoundsException: " + e.getMessage()); } catch (IOException e) { System.err.println("Caught IOException: " + e.getMessage()); } O primeiro bloco irá ser executado quando for disparada uma exceção de índice do vetor,e o outro quando ocorrer um erro de escrita no arquivo. A granularidade permitida é muito grande, como podemos ver. Mas é possível definirapenas alguns (ou mesmo um) blocos para todas as exceções. Criar código diferenciado paraerros de acesso a um vetor ou erro no disco pode ser pouco produtivo. O Java tem a capacidadede agrupar as exceções, baseado na organização hierárquica das mesmas. Quanto mais próximo da classe “folha”, mais específica é o tratamento da exceção.Podemos escolher em tratar as classes mais próximas do “tronco” ou mesmo da “raiz”. Veja a imagem:9
  • 10. Assim, podemos reescrever nosso exemplo de modo que apenas um bloco catch podelidar com todas as exceções: try { ... } catch (Exception e) { System.err.println("Exception caught: " + e.getMessage()); } A classe Exception é a mais alta na hierarquia Throwable. Assim, qualquer exceção queocorrer será tratada por esse bloco. A idéia em si é que ele basta para tratar de erros gerais, mas éum tanto inútil para um tratamento adequado, perdendo um pouco da vantagem de tratamentoque o Java fornece. Finalmente, temos o bloco finally.O Bloco finally Todo try deve ter pelo menos um catch. Existe mais um bloco de código que pode serdefinido, mas ele não é obrigatório. Ele existe para que se possa realizar certas atividades quedevem ser feitas independentemente do curso de execução ter gerado exceções ou não. Umexemplo é fechar um arquivo ou conexão com o banco de dados. Lembremos novamente de nosso exemplo da página 8. Três casos ocorrer.1) O FileWriter falha e lança uma IOException.2) O victor.elementAt(i) falha e lança uma ArrayIndexOutOfBoundsException.3) Tudo dá certo, e nenhuma exceção é gerada. Certas instruções devem ser executadas para qualquer um dos casos. O bloco finally servejustamente para isso. Suas instruções serão executadas sempre, com exceções ou sem elas. Suadefinição permite que eliminemos código duplicado e facilita o encerramento de uma rotina.10
  • 11. Exercícios:1. O código abaixo é válido ? try { ... } finally { ... }2.Quais as exceções que serão capturadas pelo bloco abaixo ? catch (Exception e) { ... }Cite uma desvantagem de usar esse tipo de classe de exceção.3.Quais as exceções que serão capturadas pelo bloco abaixo ? ... } catch (Exception e) { ... } catch (ArithmeticException a) { ... }Há alguma coisa errada com esses blocos ? O código compila ?11
  • 12. Entrada e saida As vezes um programa necessita trazer informação de uma fonte externa ou enviarinformação para um destino fora do programa. A informação pode estar em qualquer lugar: umarquivo em disco, na rede, em outro programa. A informação também pode ser de qualquer tipo:um objeto, um caracter, uma imagem, um som... Para lidar com essas informações, o Java utiliza o conceito de stream. Ele pode serentendido como se fosse um “tubo”, onde as informações são enviadas em fluxo, que são lidas(ou escritas). Veja o desenho: Não importa de onde o dado esteja vindo (ou indo), e não importa seu tipo. Os algoritmosque lidam com streams tratam de maneira sequencial do dados: abrir o stream enquanto houver informação ler informação fechar o stream O pacote java.io possui classes que tratam e criam os streams. Basicamente, temosstreams para leitura de caracteres e para leitura de bytes. Os primeiros possibilitam a leitura eescrita de palavras de 16 bits, e são originários da classe abstrata java.io.Reader e java.io.Writer.12
  • 13. Os streams para leitura de bytes lidam com palavras de 8 bits, e são subclasses dejava.io.InputStream e java.io.OutputStream. Os streams mais fáceis de entender são os relacionados a arquivos. Segue um exemplo deprograma que copia um arquivo de um stream para outro.import java.io.*; public class Copy { public static void main(String[] args) throws IOException { File inputFile = new File("entrada.txt");13
  • 14. File outputFile = new File("saida.txt"); FileReader in = new FileReader(inputFile); FileWriter out = new FileWriter(outputFile); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); } } Como podemos ver, o programa é muito simples. Ele abre um FileReader no arquivoentrada.txt e abre um FileWriter no arquivo saida.txt. O programa lê caracteres enquanto houverno stream de entrada e os escreve no stream de saída. Quando terminar, ele fecha ambos osstreams. O assunto é um tanto extenso, e esse curso se propõe a passar apenas a idéia básica sobreo assunto. Temos capacidade de gerar ou ler streams com arquivos zipados, serializar objetos(artifício utilizado para comunicação remota) e mesmo acessar arquivos de maneira nãosequencial. Introducao ao Swing O pacote Swing é parte da JavaTM Foundation Classes (JFC) na plataforma Java. Existena linguagem como pacote de extensão desde a versão 1.1, e serve basicamente para auxiliar aspessoas a construirem GUIs (Guided User Interface). O Swing fornece todos os componentesbásicos, de botões a tabelas.Seu primeiro Swing A maneira mais fácil de ensinar a utilizar o Swing mostrando código. Vamos a umprograma bem simples, que exibe “Alo Mundo”. import javax.swing.*; public class HelloWorldSwing { public static void main(String[] args) { JFrame frame = new JFrame("HelloWorldSwing"); final JLabel label = new JLabel("Hello World"); frame.getContentPane().add(label); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack();14
  • 15. frame.setVisible(true); } } Esta é a aplicação mais simples que se pode escrever. Vamos analisar o código linha alinha. Inicialmente, como sempre, importamos os pacotes que iremos utilizar. No caso,javax.swing.*. A outra linha interessante é a onde se define nossa raiz, ou container. Ele é oelemento principal, e onde iremos “dependurar” tudo que queremos que apareca em nossa tela.No nosso caso, eh o JFrame. Ele permite que outros componentes sejam adicionados a ele, e tema capacidade de gerenciar eventos. Existem outros 2 containers Swing: JDialog e JApplet (esseúltimo, utilizado apenas para Applets). Cada objeto JFrame implementa uma única janela principal, que possui decorações. Elassão a borda, o título e botões para maximizar, minimizar e fechar a janela. Uma aplicação Swingusa normalmente pelo menos um JFrame. Nosso frame tem um componente. Um label, onde escrevemos “Alo Mundo”. As duaslinhas de código abaixo constroem e adicionam o componente ao frame: final JLabel label = new JLabel("Hello World"); frame.getContentPane().add(label); Para fechar a janela quando o botão de fechar é clicado, devemos incluir a linha abaixono nosso programa: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); O comportamento padrão de um frame quando o botão de fechar é clicado é esconder ajanela, coisa que não desejamos. A linha onde consta o método pack() determina o tamanho do frame de modo que todosos componentes estejam em um tamanho padrão. Esse método utiliza algumas propriedades dosistema para criar e colocar o frame em um tamanho considerado adequado. A última linha, que chama o método setVisible(), faz com que o frame apareça na tela. Veja o resultado:15
  • 16. Notas sobre o Swing: Para aparecer na tela, todos os componentes devem ser adicionados e estarem presentesem alguma parte de hierarquia, que se inicia na raiz (JFrame, JDialog ou JApplet). Todos os componentes raiz possuem um content pane, que contém a parte visível do queestamos montando, como mostrado na figura abaixo: Opcionalmente, você pode adicionar um menu a um componente raiz. O menu éposicionado diretamente na raiz, fora do content pane. BibliografiaThe Java Tutorial – http://www.sun.com/docsCore Java – Horstmann, Cay S., Cornell, Gary. Makron BooksProibida a alteração, reprodução e cópia de parte deste material para qualquer finalidade sem a permissão do Centrode Computação da Unicamp.A utilização deste material é permitida desde que conste a autoria do mesmo.© 2002 Centro de Computação da Unicamp.16