Você está na página 1de 39

Programao Orientada por Objectos

87

Tratamento de Erros com Excepes


Idealmente os erros de um programa deviam ser apanhados em tempo de compilao porque cdigo errado no deveria ser executado. Mas como nem todos os erros podem ser detectados em tempo de compilao, deve existir um formalismo de tratamento de erros em tempo de execuo. Em muitas linguagens o formalismo consiste no retorno de um valor especial ou na colocao de uma flag pela funo na qual se verificou o erro, e o programa que chamou a funo devia testar o valor retornado ou a flag, e determinar qual o problema. Mas, a maior parte das vezes, os programas no testam as condies de erro. Se testassem todos os potenciais erros sempre que uma funo era chamada o cdigo tornar-se-ia ilegvel.

Benefcios das excepes No ponto do programa onde ocorre um problema, conhecem-se as caractersticas do problema que ocorreu, mas em geral, nesse contexto (contexto corrente) no se tem informao suficiente para lidar com o problema. Num contexto mais alto, noutra parte do programa, existe a informao necessria para decidir o que fazer. Outro benefcio das excepes resulta num programa limpo de cdigo de tratamento de erros. No necessrio testar a ocorrncia de um erro particular e trat-lo em vrios stios de um programa. A excepo garante que o erro tratado. Deste modo o problema s tratado num stio. Alm de se poupar cdigo, separa-se cdigo com o que se pretende fazer, do cdigo de tratamento de erros.

Lanamento de uma excepo Uma excepo (condio excepcional) um problema que no permite a continuao do mtodo ou scope em execuo. Quando ocorre uma excepo no se pode continuar o processamento corrente porque no se tem informao necessria para tratar do problema no contexto corrente e relega-se o problema para um contexto mais alto, lanando uma excepo. Quando se lana uma excepo (usa-se a palavra-chave throw), um objecto excepo criado (atravs da chamado de um construtor da respectiva classe) e sai-se do mtodo ou do scope corrente, sendo retornada a referncia ao objecto excepo criado. O fluxo de execuo corrente parado e passa do contexto corrente para o local de tratamento da excepo para onde tambm passada a referncia do objecto excepo. Exemplo de lanamento de uma excepo: if (t == null) throw new NullPointerException();

DEI - ISEP

Fernando Mouta

88

Programao Orientada por Objectos

Em todas as excepes standard (classes) h 2 construtores: um sem argumentos, e outro com 1 argumento do tipo String. Normalmente lana-se uma excepo de uma classe diferente para cada tipo diferente de erro, para que no contexto mais amplo se possa determinar o que fazer (tomar a deciso apropriada) apenas atravs do conhecimento do tipo de objecto excepo. Quando uma excepo lanada o mecanismo de tratamento de excepes toma conta do controlo do fluxo do programa e termina a execuo do mtodo no qual a excepo lanada, assim como os mtodos dos quais este mtodo foi chamado e a execuo continua numa parte do programa que se destina a tratar excepes daquele tipo ( exception handler ).

Bloco try - regio guardada Para que throw no cause a sada de um mtodo, deve existir dentro desse mtodo um bloco para capturar a excepo Uma excepo lanada capturada imediatamente a seguir a um bloco try por clusulas denotadas pela palavra-chave catch, designadas clusulas catch ou clusulas de tratamento de excepes (exception handlers). Cada clusula catch toma 1 e s 1 argumento de um tipo particular. try { cdigo que pode gerar excepes } catch (Type1 id1) { // tratamento de excepes do tipo Type1 } catch (Type2 id2) { // tratamento de excepes do tipo Type2 ... } Normalmente o tratamento da excepo baseado no tipo da excepo sem necessidade de usar o identificador, mas em qualquer dos casos o identificador tem de ser declarado. As clusulas catch devem aparecer directamente depois do bloco try, tendo cada clusula sempre 1 s argumento. Este tratamento de excepes separa o cdigo colocado num bloco try (cdigo com o que se pretende fazer), do tratamento de erros colocado nas clusulas onde se capturam e tratam as excepes (clusulas catch). Se uma excepo lanada, o mecanismo de tratamento de excepes procura a primeira clusula catch com um argumento do tipo da excepo. Se encontra executa o cdigo dessa clusula catch e sai.

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos Lista de Especificao das Excepes

89

Java obriga a declarar as excepes que um mtodo lana na declarao do mtodo depois da lista de argumentos. A especificao das excepes feita atravs da palavrachave throws seguida de uma lista de todos os tipos de potenciais excepes. void mtodo() throws excepo1, excepo2 { ... } Se a especificao das excepes declaradas no estiver correcta, o compilador detecta isso e informa que determinada excepo deve ser tratada, ou ento indicada na especificao das excepes, significando que pode ser lanada do mtodo.

Java contem um classe chamada Throwable que descreve tudo o que pode ser lanado como excepo. Throwable tem 2 subclasses: Error descreve erros de compilao e do sistema; Exception o tipo de erros que podem ser lanados de qualquer mtodo das classes de bibliotecas standard ou de mtodos que escrevemos. Todas as excepes que possam ocorrer so objectos de classes que so subclasses do tipo Exception. possvel capturar qualquer tipo de excepo capturando uma excepo do tipo base Exception. catch (Exception e) { System.out.println(Capturando a excepo + e.getMessage()); }

Ao objecto excepo podem aplicar-se mtodos da classe Throwable, ou ainda mtodos da classe Object (superclasse de todas as classes). Mtodos da classe Throwable String getMessage() - retorna a mensagem de erro associada com a excepo. String toString() - retorna uma descrio do objecto. void printStackTrace() - imprime para o standard erro. void printStackTrace(PrintStream) - imprime para um stream especificado (por exemplo System.out). printStackTrace() mostra a sequncia dos mtodos invocados que levaram ao ponto onde a excepo foi lanada. Mtodo da classe Object: getClasse() - retorna um objecto pertencente classe Class representando a classe desse objecto excepo. A este objecto retornado pode aplicar-se o mtodo getName(), que retorna o nome da classe.

DEI - ISEP

Fernando Mouta

90

Programao Orientada por Objectos

Criao de Excepes Podemos criar as nossas prprias excepes para denotar algum erro especial. Para criar uma classe de excepes necessrio herdar de um tipo existente de excepes. Mostramos, em seguida, um exemplo no qual o mtodo main() chama o mtodo f(), o qual chama o mtodo divide(). O mtodo divide() pode lanar uma excepo.

Apresentamos em seguida vrias vrias situaes. Consideremos em todas essas situaes, difinida a seguinte classe Excepcao1: class Excepcao1 extends Exception { public Excepcao1() { } public Excepcao1(String msg) { super(msg); } } 1. Sem tratamento das excepes. O programa d erro de execuo. public class Teste0 { public static int divide(int a,int b) { return a/b; } public static int f(int a,int b) { return divide(a, b); } public static void main(String args []) { System.out.println(f(5, 2)); System.out.println(f(3, 0)); System.out.println(f(4, 1)); } }

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos

91

2. O mtodo divide() pode lanar uma excepo, mas no capturada nem declarada. D erro de compilao.

public class Teste { public static int divide(int a,int b) { if (b==0) throw new Excepcao1("Divisao por zero!"); return a/b; } public static int f(int a,int b) { return divide(a, b); } public static void main(String args []) { System.out.println(f(5, 2)); System.out.println(f(3, 0)); System.out.println(f(4, 1)); } } error J0122: Exception 'Excepcao1' not caught or declared by 'int Teste.divide(int a, int b)'

3. O mtodo divide() declara a excepo, mas o mtodo f() no a captura nem a declara. D erro de compilao. public class Teste { public static int divide(int a,int b) throws Excepcao1 { if (b==0) throw new Excepcao1("Divisao por zero!"); return a/b; } public static int f(int a,int b) { return divide(a, b); } public static void main(String args []) { System.out.println(f(5, 2)); System.out.println(f(3, 0)); System.out.println(f(4, 1)); } } error J0122: Exception 'Excepcao1' not caught or declared by 'int Teste.f(int a, int b)'

DEI - ISEP

Fernando Mouta

92

Programao Orientada por Objectos

4. O mtodo divide() e o mtodo f() declaram a excepo, mas o mtodo main() no a captura nem a declara. D erro de compilao. public class Teste { public static int divide(int a,int b) throws Excepcao1 { if (b==0) throw new Excepcao1("Divisao por zero!"); return a/b; } public static int f(int a,int b) throws Excepcao1 { return divide(a, b); } public static void main(String args []) { System.out.println(f(5, 2)); System.out.println(f(3, 0)); System.out.println(f(4, 1)); } } error J0122: Exception 'Excepcao1' not caught or declared by 'void Teste.main(String[] args)'

5. Os mtodos divide(), f() e main() declaram a excepo. O programa compila mas d erro de execuo. public class Teste { public static int divide(int a,int b) throws Excepcao1 { if (b==0) throw new Excepcao1("Divisao por zero!"); return a/b; } public static int f(int a,int b) throws Excepcao1 { return divide(a, b); } public static void main(String args []) throws Excepcao1 { System.out.println(f(5, 2)); System.out.println(f(3, 0)); System.out.println(f(4, 1)); } }

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos

93

6. A excepo capturada no mtodo divide(). O mtodo main() completado. public class Teste { public static int divide(int a,int b) { try { if (b==0) throw new Excepcao1("Divisao por zero!"); return a/b; } catch (Exception e) { e.printStackTrace(); System.out.println("Resultado nao valido:"); return 0; } } public static int f(int a,int b) { return divide(a, b); } public static void main(String args []) { System.out.println(f(5, 2)); System.out.println(f(3, 0)); System.out.println(f(4, 1)); } }

7. A excepo capturada no mtodo f(). O mtodo main() completado.

public class Teste { public static int divide(int a,int b) throws Excepcao1 { if (b==0) throw new Excepcao1("Divisao por zero!"); return a/b; }

DEI - ISEP

Fernando Mouta

94

Programao Orientada por Objectos public static int f(int a,int b) { try { return divide(a, b); } catch (Exception e) { e.printStackTrace(); System.out.println("Resultado nao valido:"); return 0; } } public static void main(String args []) { System.out.println(f(5, 2)); System.out.println(f(3, 0)); System.out.println(f(4, 1)); }

8. A excepo capturada no mtodo main(). O mtodo main() no completado, porque o lanamento da excepo causado pela invocao da 2 instruo do mtodo main() causa o abandono do cdigo do bloco try.

public class Teste { public static int divide(int a,int b) throws Excepcao1 { if (b==0) throw new Excepcao1("Divisao por zero!"); return a/b; } public static int f(int a,int b) throws Excepcao1 { return divide(a, b); }

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos public static void main(String args []) { try { System.out.println(f(5, 2)); System.out.println(f(3, 0)); System.out.println(f(4, 1)); } catch (Exception e) { e.printStackTrace(); System.out.println("Resultado nao valido:"); // return 0; } } }

95

Excepes em subclasses Quando se reescreve um mtodo s se podem lanar excepes que foram especificadas no mtodo da classe base. Deste modo cdigo que funciona com a classe base tambm funcionar com qualquer objecto derivado da classe base incluindo excepes. Clusula finally Por vezes h a necessidade de executar algum cdigo, quer ocorra ou no uma excepo num bloco try, para colocar qualquer coisa no seu estado inicial, tal como um ficheiro aberto ou uma ligao a outro computador. Isso consegue-se usando uma clusula finally no fim do tratamento das excepes. try { // . . . regio guardada } catch ( Excepo1 e1 ) { ... } catch ( Excepo2 e2 ) { ... } finally { ... }

DEI - ISEP

Fernando Mouta

96 Exemplo:

Programao Orientada por Objectos

public class Teste1 { static int count = 0; public static void main (String args []) { while (true) { try { if (count++ == 0) throw new Exception(); System.out.println("Excepcao lancada"); } catch (Exception e) { System.out.println("Execepcao capturada"); } finally { System.out.println("Clausula finally"); if (count == 2) break; } } } }

Clusula catch que captura uma excepo lanada Na determinao da clusula catch que captura uma excepo lanada, o mecanismo de tratamento das excepes procura a primeira clusula catch para a qual o tipo de excepo o tipo ou subtipo do argumento da clusula catch. class A extends Exception { } class B extends A { } public class Teste2 { public static void main(String args []) { try { throw new B(); } catch (A a) { System.out.println("Capturada excepcao A"); } } }

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos

97

A excepo B capturada pela clusula catch(A a).

O cdigo seguinte dar erro de compilao porque a clusula catch (B b) nunca ser atingida: class A extends Exception { } class B extends A { } public class Teste { public static void main(String args []) { try { throw new B(); } catch (A a) { System.out.println(Capturada excepo A); } catch (B b) { System.out.println(Capturada excepo B); } } } Mensagem de erro produzida: error J0102: Handler for 'B' hidden by earlier handler for 'A'

Relanamento de uma Excepo (Rethrowing an exception)


Para voltar a lanar uma excepo que foi capturada executa-se throw referncia. Uma excepo depois de capturada (por uma clusula catch) pode voltar a ser relanada para ser tratada num contexto mais alto. catch (Exception e) { System.out.println(Excepo:); e.printStackTrace(); throw e; }

DEI - ISEP

Fernando Mouta

98

Programao Orientada por Objectos

Exemplo: public class RelancamentoExcepcoes { public static void f() throws Exception { System.out.println("No metodo f()"); throw new Exception("Excepcao lancada em f()"); } public static void g() throws Throwable { try { f(); } catch (Exception e) { System.out.println("No metodo g()"); e. printStackTrace(); throw e; } } public static void main(String args []) throws Throwable { try { g(); } catch (Exception e) { System.out.println("Capturada no main, e.printStackTrace()"); e.printStackTrace(); } System.in.read(); } }

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos

99

Excepes RunTimeException Java realiza verificaes, em tempo de execuo, de excepes da classe RuntimeException. Excepes deste tipo so automaticamente lanadas e no necessrio inclu-las nas especificaes das excepes. Todos os tipos de potenciais excepes tm de ser includos na declarao de um mtodo (lista com a especificao das excepes) excepto excepes do tipo RuntimeException. Excepes do tipo RuntimeException representam erros de programao. Estes erros tais como NullPointException ou ArrayIndexOutOfBoundsException se no forem capturados so reportados na sada do programa auxiliando no processo de depurao (debugging). Excepes do tipo RuntimeException ou de classes que herdam deste tipo no necessitam de pertencer lista de especificao de excepes na declarao de um mtodo. Exemplo: public class RuntimeExcepcao { static void f() { throw new RuntimeException(Do metodo f()); } public static void main(String args()) { f(); } } Sada produzida:

DEI - ISEP

Fernando Mouta

100

Programao Orientada por Objectos

Se uma excepo do tipo RuntimeException lanada e no apanhada, na sada do programa printStackTrace() chamado para essa excepo.

Exemplos
Exemplo 1: Programa que efectua 3 leituras de um nmero inteiro. Se a entrada no pode ser convertida num nmero, lana uma excepo que capturada e imprime a mensagem Errado. import java.io.*; class Numero1{ public static String lerString(String msg) throws java.io.IOException { DataInputStream din = new DataInputStream(System.in); System.out.print(msg); return din.readLine(); } public static void main(String args []) throws java.io.IOException { int n; for(int i=0; i<3; i++) { String s = lerString("Digite um numero: "); try { n = Integer.parseInt(s); System.out.println("Numero valido: " +n); } catch (NumberFormatException nfe) { //nfe.printStackTrace(); System.out.println("Errado."); } } System.out.println("Fim."); System.in.read(); } }

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos

101

Exemplo 2: Programa que efectua a leitura de um nmero inteiro at a entrada poder ser convertida num nmero. import java.io.*; class Numero2{ public static String lerString(String msg) throws java.io.IOException { DataInputStream din = new DataInputStream(System.in); System.out.print(msg); return din.readLine(); } public static void main(String args []) throws java.io.IOException { boolean lido = false; int n; do { String s = lerString("Digite um numero: "); try { n = Integer.parseInt(s); lido = true; } catch (NumberFormatException nfe) { //nfe.printStackTrace(); System.out.println("Tente outra vez:"); } } while (!lido); System.out.println("Fim."); System.in.read(); } }

DEI - ISEP

Fernando Mouta

102

Programao Orientada por Objectos

Ficheiros e Streams
O armazenamento de dados em variveis, arrays ou objectos sempre temporrio, porque os dados so perdidos quando as variveis ou as referncias aos objectos saem fora do mbito de validade ou quando o programa termina. Os ficheiros so usados para reteno dos dados. Dados mantidos em ficheiros designam-se por dados persistentes. Os browsers no permitem aos applets ler ou escrever em ficheiros por razes de segurana. Por isso, programas de processamento de ficheiros so implementados como aplicaes. Para realizar processamento de ficheiros em Java temos de importar o package java.io.

Apresenta-se a seguir a hierarquia de classes de ficheiros e streams mais importantes: Object File InputStream FileInputStream FiterInputStream DataInputStream BufferedInputStream ObjectInputStream OutputStream FileOutputStream FiterOutputStream DataOutputStream BufferedOutputStream PrintStream ObjectOutputStream RandomAccessFile

As entradas e sadas de dados em Java so baseados no uso de streams, que so sequncias de bytes ou caracteres que fluem de uma fonte para um destino atravs de um dado caminho de comunicao. InputStream e OutputStream so classes abstractas que declaram mtodos para realizar input e output. As classes derivadas destas reescrevem estes mtodos. As classes FileInputStream e FileOutputStream destinam-se a criar objectos que abrem ficheiros para leitura ou para escrita, passando aos construtores uma string com o nome do ficheiro. Um ficheiro aberto para escrita, se j existe inicializado (perdendo-se todo o seu contedo) e se no existe criado.

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos

103

No h o conceito de abrir um ficheiro para escrita de texto ASCII ou de dados binrios. Pode-se escrever qualquer coisa sem fazer distino entre caracteres e outros dados.

Interface DataInput e interface DataOutput O interface DataInput implementado pela classe DataInputStream e pela classe RandomAccessFile, declarando mtodos para ler tipos primitivos de dados de streams. O interface DataOutput implementado pela classe DataOutputStream e pela classe RandomAccessFile, declarando mtodos para escrever tipos primitivos de dados em streams. Os interfaces DataInput e DataOutput fornecem mtodos que suportam o input/output independente da mquina.

Escrever Dados num Ficheiro Para abrir um ficheiro para escrita, usa-se um FileOutputStream construdo com um objecto String ou File para o nome do ficheiro. Para escrever de um modo formatado temos que construir um objecto DataOutputStream usando como argumento do construtor o objecto FileOutputStream. A classe DataOutputStream fornece a capacidade de escrever objectos String e tipos primitivos para uma stream de sada. Podemos escrever dados num ficheiro criando um objecto do tipo DataOutputStream passando como argumento ao seu construtor um objecto FileOutputStream representando o ficheiro. FileOutputStream fileOutput = new FileOutputStream(info.dat); DataOutputStream output = new DataOutputStream(fileOutput); Esta tcnica designa-se por encadeamneto de objectos e normalmente realizada apenas pela instruo: DataOutputStream output = new DataOutputStream( new FileOutputStream(info.dat));

Ler Dados de um Ficheiro Para abrir um ficheiro para leitura, usa-se um FileInputStream construdo com um objecto String ou File para o nome do ficheiro. Para ler de um modo formatado temos que construir um objecto DataInputStream usando como argumento do construtor o objecto FileInputStream.

DEI - ISEP

Fernando Mouta

104

Programao Orientada por Objectos

A classe DataInputStream fornece a capacidade de ler objectos String e tipos primitivos de uma stream de entrada. Podemos ler dados de um ficheiro criando um objecto do tipo DataInputStream passando como argumento ao seu construtor um objecto FileInputStream representando o ficheiro. FileInputStream fileInput = new File InputStream(info.dat); DataInputStream input = new DataInputStream(fileInput); De um modo idntico escrita em ficheiros este encadeamneto de objectos normalmente realizada apenas pela instruo: DataInputStream input = new DataInputStream( new FileInputStream(info.dat));

Excepes Quando se cria um objecto FileOutputStream para abrir um ficheiro, o programa testa se a operao de abertura teve sucesso. Se a operao falha (por exemplo se no h espao de disco disponvel) gera-se uma excepo IOException que pode ser capturada pelo programa. Exemplo: try { DatOutputStream output = new DataOutputStream( new FileOutputStream(info.dat)); } catch (IOException e) { System.err.println(Ficheiro no aberto\n + e.toString()); System.exit(1); } Neste exemplo se a tentativa de abrir o ficheiro gera uma excepo IOException a mensagem de erro mostrada e o programa termina. O argumento do mtodo exit() retornado ao ambiente do qual o programa foi invocado, normalmente o sistema operativo. O argumento 0 indica que o programa terminou normalmente e qualquer outro valor indica que o programa terminou devido a um erro. Este valor pode ser usado pelo ambiente que invocou o programa para reagir em conformidade.

De um modo semelhante, quando se cria um objecto FileInputStream para abrir um ficheiro para leitura, o programa testa se a operao de abertura teve sucesso. Se a operao falha (ficheiro no existente, ou no permisso de leitura do ficheiro) gera-se uma excepo IOException que pode ser capturada pelo programa.

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos Exemplo: try { DataInputStream input = new DataInputStream( new FileInputStream(info.dat)); } catch (IOException e) { System.err.println(Ficheiro no aberto\n + e.toString()); System.exit(1); }

105

Os dados devem ser lidos de ficheiros no mesmo formato no qual foram escritos no ficheiro. Os interfaces DataInput e DataOutput definem mtodos que transmitem tipos primitivos de dados atravs de um stream. As classes DataInputStream e DataOutputStream fornecem uma implementao para cada interface. Os mtodos de leitura e escrita existentes aos pares para cada tipo so: Leitura: boolean byte short int long float double char String readBoolean() readByte() readShort() readInt() readLong() readFloat() readDouble() readChar() readUTF() Escrita: void writeBoolean(boolean) void writeByte(byte) void writeShort(short) void writeInt(int) void writeLong(long) void writeFloat(float) void writeDouble(double) void writeChar(char) void writeUTF(String) Tipo: boolean byte short int long float double char String

Os mtodos readUTF() e writeUTF() lem e escrevem no formato UTF. UTF (Unicode Transmission Format) o formato de transmisso Unicode. uma forma binria que compacta caracteres Unicode de 16 bits em bytes de 8 bits. De um modo semelhante, quando se cria um objecto FileInputStream para abrir um ficheiro para leitura, o programa testa se a operao de abertura teve sucesso. Se a operao falha (ficheiro no existente, ou no permisso de leitura do ficheiro) gera-se uma excepo IOException que pode ser capturada pelo programa. Exemplo: try { DataInputStream input = new DataInputStream( new FileInputStream(info.dat)); } catch (IOException e) { System.err.println(Ficheiro no aberto\n + e.toString()); System.exit(1); }

DEI - ISEP

Fernando Mouta

106

Programao Orientada por Objectos

Para alm destes mtodos ainda referimos outro de leitura: String readLine() throws IOException l uma String at atingir \n, \r ou o par \r\n. A sequncia fim de linha no includa na String. Retorna null se atinge o fim do input. E outro de escrita: void writeChars(String s) throws IOException escreve uma string como uma sequncia de char. Uma string escrita com o mtodo writeChars() deve ser lida usando um ciclo com readChar. necessrio escrever primeiro o comprimento da string ou usar um separador para marcar o fim.

Os mtodos complementares, tais como writeDouble() e readDouble(), permitem recuperar a informao armazenada num ficheiro, mas para os mtodos de leitura funcionarem correctamente deve-se conhecer a colocao exacta dos dados no ficheiro. Portanto ou os dados so armazenados no ficheiro num formato fixo ou informao extra deve ser armazenada no ficheiro que permita determinar onde e como os dados esto localizados (por exemplo precedendo cada item de dados por um par de bytes que informam o tipo e comprimento). O mtodo close() fecha uma stream de entrada ou de sada e liberta os recursos associados com a stream. No caso de uma stream de sada qualquer dado escrito para a stream armazenado antes de a stream ser desalocada. O mtodo available() retorna o nmero de bytes que podem ser lidos sem bloqueamento, o que para um ficheiro significa at ao fim do ficheiro.

Exemplos Exemplo 1: Programa que grava num ficheiro os primeiros 1000 nmeros naturais e em seguida l o mesmo ficheiro testando o fim de ficheiro com o mtodo available().

import java.io.*; public class File1 { public static void main (String args []) throws java.io.IOException { int [] valores = new int[1000]; for (int i=0; i<1000; i++) valores[i]=i+1;

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos FileOutputStream fileOutput = new FileOutputStream("out.txt"); DataOutputStream output = new DataOutputStream(fileOutput); for (int i=0; i<valores.length; i++) output.writeInt(valores[i]); output.close(); FileInputStream fileInput = new FileInputStream("out.txt"); DataInputStream input = new DataInputStream(fileInput); int v; while (input.available() != 0) { v=input.readInt(); System.out.println(v); } input.close(); System.in.read(); } }

107

Exemplo 2:

Aplicao que grava no ficheiro nomes.dat um array de strings, usando o mtodo writeChars() e um separador para marcar o fim de cada string. O tamanho do array gravado no incio para permitir na leitura criar um array do mesmo tamanho. Depois o programa abre o ficheiro para leitura, l o seu contedo para outro array de strings que cria, e mostra essas strings.

import java.io.*; public class DataIO { static char SEP = '|'; static String readChars(DataInputStream in, char separador) throws IOException { String s=""; char ch = in.readChar(); while (ch != separador) { s += ch; ch = in.readChar(); } return s; } public static void writeData(String[] s, String fich) throws IOException { FileOutputStream fout = new FileOutputStream(fich); DataOutputStream out = new DataOutputStream(fout); out.writeInt(s.length); for (int i=0; i< s.length; i++) { out.writeChars(s[i]);

DEI - ISEP

Fernando Mouta

108 out.writeChar(SEP); } out.close(); }

Programao Orientada por Objectos

public static String [] readData(String fich) throws IOException { FileInputStream fin = new FileInputStream(fich); DataInputStream in = new DataInputStream(fin); String [] s2 = new String[in.readInt()]; for (int i=0; i< s2.length; i++) s2[i] = readChars(in, SEP); in.close(); return s2; } public static void main (String args []) throws java.io.IOException { String [] nomes ={"Miguel", "Ana", "Carlos", "Joaquim"}; writeData(nomes, "nomes.txt"); String [] nomes2; nomes2 = readData("nomes.txt"); for (int i=0; i<nomes2.length; i++) System.out.println(nomes2[i]); System.in.read(); } }

Exemplo 3:

Aplicao que cria vrios objectos da classe Conta, coloca-os num array e grava-os num ficheiro. Em seguida cria um novo vector de referncias para objectos Conta e preenche-o com objectos lidos do mesmo ficheiro. Finalmente mostra o contedo do vector criado. A classe Conta permite construir uma conta com um dado nmero (num), primeiro nome (pNome), ltimo nome (uNome), e saldo (saldo), e tambm gravar num dado stream o contedo de um objecto Conta (writeConta()) assim como ler de um stream o contedo de um objecto (readConta()) criando o respectivo objecto.

import java.io.*; class Conta { private int num; private String pNome, uNome; private double saldo; public Conta(int num, String pNome, String uNome, double saldo) { this.num = num; this.pNome = pNome;

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos this.uNome = uNome; this.saldo = saldo; } public void writeConta(DataOutputStream out) throws java.io.IOException { out.writeInt(num); out.writeUTF(pNome); out.writeUTF(uNome); out.writeDouble(saldo); } public static Conta readConta(DataInputStream in) throws java.io.IOException { return new Conta( in.readInt(), in.readUTF(), in.readUTF(), in.readDouble() ); } public void print() { System.out.println(num + ": " + pNome + " " + uNome + " -> saldo = " + saldo); } }

109

public class DataIO { static void writeData(Conta [] c, String ficheiro) throws java.io.IOException { DataOutputStream out = new DataOutputStream( new FileOutputStream( ficheiro ) ); out.writeInt(c.length); for (int i=0; i<c.length; i++) c[i].writeConta(out); out.close(); } static Conta [] readData (String ficheiro) throws java.io.IOException { DataInputStream in = new DataInputStream( new FileInputStream(ficheiro)); Conta [] c = new Conta[in.readInt()]; for (int i=0; i< c.length; i++) c[i] = Conta.readConta(in); in.close(); return c; }

DEI - ISEP

Fernando Mouta

110

Programao Orientada por Objectos public static void main (String args []) throws java.io.IOException { Conta vect[] = new Conta[3]; vect[0] = new Conta (1, "Carlos", "Miguel", 4234.21); vect[1] = new Conta (2, "Jorge", "Silva", 231.15); vect[2] = new Conta (3, "Manuel", "Santos", 8421.5); writeData(vect, "contas.dat"); Conta [] v = readData("contas.dat"); for (int i=0; i<v.length; i++) v[i].print(); System.in.read(); }

} O mtodo writeData da classe DataIO abre o ficheiro para escrita e escreve o tamanho do array. Depois escreve, objecto a objecto, o contedo do array. Finalmente fecha o ficheiro. O mtodo readData da classe DataIO abre o ficheiro para leitura, l o tamanho do array e cria um array de objectos. Depois, para cada elemento do array, invoca o mtodo readData da classe Conta que retorna um objecto criado com o contedo lido do ficheiro. Finalmente fecha o ficheiro.

RandomAccessFile RandomAccessFile uma classe que descende directamente da classe Object, mas que implementa os interfaces DataInput e DataOutput. Esta classe fornece a capacidade ler ou escrever directamente em localizaes especficas de um ficheiro (movendo o apontador do ficheiro para uma posio arbitrria). Este acesso aleatrio suportado pelos seguintes mtodos: getFilePointer() - retorna a localizao corrente do apontador do ficheiro; seek() - move o apontador do ficheiro para uma nova localizao; length() - retorna o tamanho do ficheiro em bytes. O construtor desta classe necessita de dois parmetros do tipo String: o 1. com o nome do ficheiro e o 2. indicando o modo de abertura do ficheiro - s para leitura (r) ou para leitura e escrita (rw). O acesso s para leitura evita um ficheiro de ser inadvertidamente modificado. import java.io.*; class File1 { public static void main (String args []) throws java.io.IOException { int [] valores = new int[10]; for (int i=0; i<1000; i++) valores[i]=i+1; int v; // escrita dos dados RandomAccessFile fo = new RandomAccessFile("out.txt", "rw"); for (int i=0; i<valores.length; i++) fo.writeInt(valores[i]); // leitura aleatria dos dados fo.close();

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos RandomAccessFile fi = new RandomAccessFile("out.txt", "r"); // Exemplo da leitura dos dados armazenados de 8 em 8 bytes for (int i=0; i<fi.length(); i=i+8) { fi.seek(i); v=fi.readInt(); System.out.println(v); } fi.close(); System.in.read(); } }

111

/* Outro exemplo com ficheiro de acesso aleatrio */ import java.io.*; class File1 { public static int lerInteiro(String s) throws java.io.IOException { System.out.print(s); BufferedReader d = new BufferedReader( new InputStreamReader(System.in)); int x = Integer.parseInt(d.readLine()); return x; } public static void main (String args []) throws java.io.IOException { int [] valores = new int[20]; for (int i=0; i<20; i++) valores[i]=i+1; RandomAccessFile fo = new RandomAccessFile("out.txt", "rw"); // escrita dos dados for (int i=0; i<valores.length; i++) fo.writeInt(valores[i]); fo.close(); // leitura e escrita aleatoria dos dados RandomAccessFile fi = new RandomAccessFile("out.txt", "r"); int i=lerInteiro("Escreva uma posicao do ficheiro: "); int v; System.out.println( "Leitura e escrita aleatoria dos dados (termine com a posicao -1)"); fi = new RandomAccessFile("out.txt", "rw"); i=lerInteiro("Escreva uma posicao do ficheiro: "); while (i!=-1) { fi.seek(i); v=fi.readInt(); System.out.println("Valor existente: " + v); int j= lerInteiro("Valor a reescrever nessa posicao : "); fi.seek(i); fi.writeInt(j); i=lerInteiro("Escreva uma posicao do ficheiro: "); } fi.close(); } }

DEI - ISEP

Fernando Mouta

112

Programao Orientada por Objectos

/* Aplicao que cria vrios objectos da classe Conta, coloca-os num array e grava-os num ficheiro. Em seguida cria um novo array de referncias para objectos Conta, preenche-o com objectos lidos do mesmo ficheiro e mostra o contedo do vector criado. Ainda criado mais um objecto da classe Conta que adicionado ao ficheiro. No fim todo o contedo do ficheiro listado. */

import java.io.*; class Conta { private int num; private String pNome, uNome; private double saldo; public Conta( int num, String pNome, String uNome, double saldo) { this.num = num; this.pNome = pNome; this.uNome = uNome; this.saldo = saldo; } public void writeConta(DataOutputStream out) throws java.io.IOException { out.writeInt(num); out.writeUTF(pNome); out.writeUTF(uNome); out.writeDouble(saldo); } public void writeConta(RandomAccessFile out) throws java.io.IOException { out.writeInt(num); out.writeUTF(pNome); out.writeUTF(uNome); out.writeDouble(saldo); } public static Conta readConta(DataInputStream in) throws java.io.IOException { return new Conta( in.readInt(), in.readUTF(), in.readUTF(), in.readDouble() ); } public void print() { System.out.println( num + ": " + pNome + " " + uNome +" -> saldo = " + saldo); } }

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos

113

class DataIO { static void writeData(Conta [] c, String ficheiro) throws java.io.IOException { DataOutputStream out = new DataOutputStream( new FileOutputStream( ficheiro ) ); out.writeInt(c.length); for (int i=0; i<c.length; i++) c[i].writeConta(out); out.close(); } static Conta [] readData (String ficheiro) throws java.io.IOException { DataInputStream in = new DataInputStream(new FileInputStream(ficheiro)); Conta [] c = new Conta[in.readInt()]; for (int i=0; i< c.length; i++) c[i] = Conta.readConta(in); in.close(); return c; } public static void main (String args []) throws java.io.IOException { Conta vect[] = new Conta[3]; vect[0] = new Conta (1, "Carlos", "Miguel", 4234.21); vect[1] = new Conta (2, "Jorge", "Silva", 231.15); vect[2] = new Conta (3, "Manuel", "Santos", 8421.5); writeData(vect, "contas.dat"); Conta [] v1 = readData("contas.dat"); for (int i=0; i<v1.length; i++) v1[i].print(); // append de uma nova Conta Conta nova = new Conta (4, "Outra", "Conta", 0.5); RandomAccessFile f = new RandomAccessFile("contas.dat", "rw"); int quant = f.readInt() + 1; f.seek(0); f.writeInt(quant); f.seek(f.length()); nova.writeConta(f); f.close(); Conta [] v2 = readData("contas.dat"); for (int i=0; i<v2.length; i++) v2[i].print(); System.in.read(); } }

DEI - ISEP

Fernando Mouta

114

Programao Orientada por Objectos

Serializao
Serializao o processo de converter objectos para um formato adequado para entrada ou sada de stream. Des-serializao o processo de voltar a converter um objecto serializado numa instncia de um objecto. Para que um objecto possa ser serializado tem de implementar o interface Serializable. O mecanismo de des-serializao para objectos restaura o contedo de cada campo com o valor e tipo que tinha quando foi escrito. Referncias a outros objectos faz com que esses objectos sejam lidos do stream. Grafos de objectos so restaurados correctamente usando um mecanismo de partilha de referncias. Novos objectos so sempre alocados quando des-serializados, o que evita que objectos existentes sejam reescritos. Os interfaces DataInput e DataOutput fornecem mtodos que suportam o input/output independente da mquina. Os interfaces ObjectInput e ObjectOutput extendem os interfaces DataInput e DataOutput para trabalhar com objectos.

Input/Output de Objectos As classes ObjectOutputStream e ObjectInputStream permitem escrever e ler de streams, objectos e tipos primitivos de dados. Estas classes implementam os interfaces ObjectOutput e ObjectInput. Dos mtodos especificados por ObjectOutput, o mtodo writeObject() o mais importante escreve objectos que implementem o interface Serializable para um stream. O interface ObjectInput declara o mtodo readObject() para ler os objectos escritos para um stream pelo mtodo writeObject(). Quando um objecto escrito na forma serializado, juntamente com o objecto armazenada informao que identifica a classe Java a partir da qual o contedo do objecto foi gravado, o que permite restaurar o objecto como uma nova instncia dessa classe. Quando um objecto serializado, todos os objectos no estticos atingveis a partir desse objecto so tambm armazenados com esse objecto. O interface Serializable usado para identificar objectos que podem ser escritos para um stream. Este interface no define quaisquer constantes ou mtodos.

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos import java.io.*; class Conta implements Serializable { private int num; private String pNome, uNome; private double saldo; public Conta( int num, String pNome, String uNome, double saldo) { this.num = num; this.pNome = pNome; this.uNome = uNome; this.saldo = saldo; } public void print() { System.out.println( num + ": " + pNome + " " + uNome +" -> saldo = " + saldo); } }

115

class DataIO { public static void main (String args []) throws java.io.IOException, java.lang.ClassNotFoundException { Conta vect[] = new Conta[3]; vect[0] = new Conta (1, "Carlos", "Miguel", 4234.21); vect[1] = new Conta (2, "Jorge", "Silva", 231.15); vect[2] = new Conta (3, "Manuel", "Santos", 8421.5); String fich = "contas.dat"; ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fich)); out.writeInt(vect.length); for (int i=0; i<vect.length; i++) out.writeObject(vect[i]); out.close(); ObjectInputStream in = new ObjectInputStream( new FileInputStream(fich)); Conta [] v = new Conta[in.readInt()]; for (int i=0; i< v.length; i++) v[i] = (Conta) in.readObject(); in.close(); for (int i=0; i<v.length; i++) v[i].print(); System.in.read(); } }

DEI - ISEP

Fernando Mouta

116

Programao Orientada por Objectos

/* Verso com a escrita e leitura de um nico objecto: o array de objectos Conta */ class DataIO { public static void main (String args []) throws java.io.IOException, java.lang.ClassNotFoundException { Conta vect[] = new Conta[3]; vect[0] = new Conta (1, "Carlos", "Miguel", 4234.21); vect[1] = new Conta (2, "Jorge", "Silva", 231.15); vect[2] = new Conta (3, "Manuel", "Santos", 8421.5); String fich = "contas.dat"; ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fich)); out.writeObject(vect); out.close(); ObjectInputStream in = new ObjectInputStream( new FileInputStream(fich)); Conta [] v = (Conta []) in.readObject(); in.close(); for (int i=0; i<v.length; i++) v[i].print(); System.in.read(); } }

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos

117

Threads
A estruturao de um programa em classes e a criao de objectos permitem dividir um programa em seces independentes. Por vezes, surge tambm a necessidade de separar um programa em subtarefas que possam correr independentemente. Cada subtarefa independente designa-se por thread. Um processo- um programa autnomo em execuo com o seu prprio espao de endereamento. Um sistema operativo multitarefa - um sistema operativo capaz de correr mais que um processo de cada vez. Um thread - um fluxo de controlo sequencial nico dentro de um processo. Um s processo pode ter mltiplos threads em execuo corrente.

Usos de Multithreading Suponhamos que temos um boto quit que quando pressionado termina o programa. Pretendemos que o boto responda rapidamente quando pressionado. Para no termos que verificar o estado do boto regularmente em todas as partes do cdigo que escrevemos, crimos um thread para fazer essa verificao e colocmo-lo a correr independentemente. Normalmente cria-se um thread para qualquer parte do programa ligada a um determinado evento ou recurso, que corre independentemente do programa principal. O tempo do CPU repartido entre todos os threads, o que reduz a eficincia da computao, mas o melhoramento no projecto do programa e no balanceamento de recursos compensa. Programas com 1 nico thread podem conseguir uma iluso de mltiplos threads quer atravs de interrupes ou por polling (algumas actividades do programa intercaladas com outras). Mas, num programa, a mistura de 2 funes no relacionadas, resulta num cdigo complexo e de difcil manuteno. Muitos problemas de software so melhor resolvidos usando mltiplos threads de controlo. Um thread de controlo pode actualizar o que mostrado, outro responde a entradas do utilizador, etc.

Criao de Threads Os threads existem definidos numa classe Thread da biblioteca standard Java. Para criar um thread, poder-se-ia criar um objecto thread: ( Thread t = new Thread(); ), e em seguida configurar o thread colocando a prioridade inicial e nome, e invocando o mtodo start() que bifurca um thread de controlo com os dados do objecto thread, e retorna.

DEI - ISEP

Fernando Mouta

118

Programao Orientada por Objectos

Depois a mquina virtual Java (interpretador) invocaria o mtodo run() do thread, tornando o thread activo at que esse mtodo run() retorne, altura em que o thread termina. Mas a implementao do mtodo run() da classe Thread no faz nada. Para ter um thread que faa qualquer coisa temos que reescrever o mtodo run() e para isso necessrio criar uma subclasse de Thread. Outro processo para criar um thread consiste em criar um objecto que implemente o interface Runnable (definindo o mtodo run()) e passando esse objecto Runnable ao construtor da classe Thread.

Classe Thread public class Thread extends Object implements Runnable Construtores: public Thread() public Thread(String nome) public Thread(Runnable obj) public Thread(Runnable obj, String nome) Mtodos de classe: public static boolean interrupted(); public static void sleep(long milis) throws InterruptedException; Mtodos instncia: public synchronized void start(); public void run(); public final void suspend(); public final void resume(); public final void stop();

start() inicia a execuo de um thread, stop() pra essa execuo, suspend() pra o thread temporariamente, resume() retoma a execuo do thread, sleep(t) pra o thread durante uma quantidade especificada de tempo em milisegundos. O mtodo run() do thread o corpo do thread. Comea a executar quando o mtodo start() do objecto thread chamado. O thread corre at que o mtodo run() retorne ou o mtodo stop() seja invocado.

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos Exemplos

119

A maneira mais simples de criar um thread herdar da classe Thread a qual possui os mtodos necessrios para criar e correr threads. O mtodo mais importante run(), o qual se deve reescrever com o cdigo que ser executado simultaneamente com os outros threads no programa.

Exemplo 1: Programa cria 2 threads que imprimem as palavras sim e nao com cadncias diferentes.

public class T extends Thread { private String palavra; private int temp; private int cont=0; public T( String p, int t, int c) { palavra = p; temp = t; cont = c; } public void run() { int i = 0; try { while ( i++ <= cont ) { System.out.println(palavra); sleep(temp); } } catch (InterruptedException e) { return; } }

public static void main(String args []) throws java.io.IOException { T t = new T("sim", 20, 10); t.start(); t = new T("nao", 100, 5); t.start(); System.in.read(); } }

DEI - ISEP

Fernando Mouta

120

Programao Orientada por Objectos

O mtodo sleep(t) da classe Thread causa uma paragem durante t milisegundos. Este mtodo pode lanar uma excepo do tipo InterruptedException se interrompido. Mas o mtodo T.run() no pode lanar excepes porque reescreve o mtodo Thread.run() e este no lana qualquer excepo. Assim necessrio capturar a excepo que sleep() pode lanar dentro do mtodo T.run(). O mtodo T.main() cria 2 objectos do tipo T (threads) e invoca o mtodo start() para cada objecto.

Exemplo 2: Programa cria 3 threads. Cada thread imprime o seu nmero seguido do valor de um contador que decrementa de 5 at 1. public class A extends Thread { private int cont = 5; private int id; private static int ultId=0; public A() { id = ++ultId; System.out.println("Criado thread n. " + id); } public void run() { while (true) { System.out.println( "Thread n. " + id + "(" + cont + ")"); if (--cont == 0) return; } }

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos

121

public static void main (String args []) throws java.io.IOException { for (int i=0; i<3; i++) // A a = new A(); // a.start(); new A().start(); System.out.println("Todos os threads iniciados."); System.in.read(); } }

Usando Runnable O interface Runnable abstrai o conceito de tudo o que executa cdigo enquanto activo. O interface Runnable declara 1 nico mtodo: public void run() A classe Thread implementa o interface Runnable. Thread pode ser estendida para criar threads com execues especficas, mas esta aproximao pode ser difcil de usar, porque Java s permite herana simples. Se uma classe estendida (como subclasse de Thread) j no pode ser estendida como subclasse de outra classe, mesmo que se precise. Implementando Runnable mais simples em muitos casos. Pode-se executar um objecto Runnable num thread prprio passando-o ao construtor Thread. Se um objecto thread construdo com um objecto Runnable, a implementao de Thread.run() invocar o mtodo run() do objecto Runnable. Vejamos uma verso Runnable do 1. exemplo apresentado. public class RunT implements Runnable { private String palavra;

DEI - ISEP

Fernando Mouta

122 private int temp; private int cont=0; public RunT( String p, int t, int c) { palavra = p; temp = t; cont = c; }

Programao Orientada por Objectos

public void run() { int i = 0; try { while ( i++ <= cont ) { System.out.println(palavra); Thread.sleep(temp); } } catch (InterruptedException e) { return; } } public static void main(String args []) throws java.io.IOException { Runnable sim = new RunT("sim", 20, 10); Runnable nao = new RunT("nao", 100, 5); Thread t = new Thread(sim); t.start(); t = new Thread(nao); t.start(); System.in.read(); } }

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos

123

Este programa muito idntico ao 1. exemplo apresentado, diferindo apenas na superclasse (Runnable versus Thread) e no mtodo main(). A implementao do mtodo run() a mesma. Nesta implementao criam-se 2 objectos Runnable (RunT) e em seguida 2 objectos Thread, passando cada objecto runnable como argumento ao construtor do objecto Thread.

Sincronizao Um thread pode realizar uma tarefa independentemente de outro thread. Tambm dois threads podem partilhar o acesso ao mesmo objecto. Quando dois threads podem modificar o mesmo dado, se ambos os threads realizam a sequncia ler-modificar-escrever de um modo intercalado podem corromper esse dado. Como exemplo suponhamos que 2 threads actualizam o saldo de uma conta (objecto c) aps um depsito, aproximadamente ao mesmo tempo.

thread1 s1 = c.getSaldo();

thread2 s2 = c.getSaldo();

s1 += deposito;

s2 += deposito;

c.setSaldo(s1);

c.setSaldo(s2);

Se as sequncias ler-modificar-escrever so realizadas intercaladamente s o ltimo depsito afecta o saldo perdendo-se a primeira modificao. Um modo de resolver este problema no permitir o acesso ao objecto enquanto estiver a ser usado. O 2 thread ter de esperar at o objecto ser liberto pelo 1 thread. Sempre que 2 threads necessitam de usar o mesmo objecto, h a possibilidade de operaes intercaladas corromperem os dados. Para sincronizar os acessos de vrios threads a um dado objecto de modo a no corromperem os dados, um thread coloca um lock (fecho) no objecto, e quando outro thread tenta aceder ao objecto, fica bloqueado at que o primeiro thread termine.

DEI - ISEP

Fernando Mouta

124

Programao Orientada por Objectos

Mas nem todos os mtodos de um thread podem corromper os dados (por exemplo mtodos de leitura). Por isso s os mtodos de um thread que possam interferir com outros so declarados synchronized.

Se um thread invoca um mtodo sincronizado num objecto, esse objecto fica no estado locked (fechado) por esse thread. Se outro thread invocar um mtodo sincronizado para esse mesmo objecto, bloquear at o objecto ser liberto do lock. A invocao de um mtodo no sincronizado prossegue normalmente sem ser afectado por qualquer lock. Cada estado locked de um objecto existe por thread, por isso a invocao de um mtodo sincronizado num objecto de dentro de outro mtodo sincronizado que colocou esse objecto no estado locked prossegue sem bloqueamento, ficando o objecto liberto de lock quando o mtodo sincronizado mais externo retorna. Threads sincronizados so mutuamente exclusivos no tempo.

O exemplo da actualizao do saldo da mesma conta aps um depsito por mais que um thread poderia ser feito a partir da seguinte classe Conta: class Conta { private double saldo; public Conta( double depositoInicial ) { saldo = depositoInicial; } public synchronized double getSaldo() { return saldo; } public synchronized void deposito( double deposito ) { saldo += deposito; } } Se o valor de um campo pode mudar, no deve ser permitido ler esse valor ao mesmo tempo que outro thread o escreve, pois a leitura pode retornar um valor invlido. O acesso ao campo deve ser sincronizado e por isso o campo no deve poder ser acedido directamente fora da classe (campo pblico ou protected). O campo deve ser declarado private e deve existir um mtodo de acesso sincronizado ao valor desse campo.

Instrues sincronizadas Uma instruo sincronizada permite executar cdigo sincronizado que coloca um objecto no estado locked durante a execuo desse cdigo sem necessidade de invocar um mtodo sincronizado para esse objecto. synchronized (expr) { instrues }

Fernando Mouta

DEI - ISEP

Programao Orientada por Objectos

125

expr deve ser colocada dentro de parnteses e deve produzir uma referncia para um objecto. Em seguida mostra-se um exemplo que troca cada elemento negativo de um array pelo seu valor absoluto. public static void valorAbs(int [] a) { synchronized (a) { for (int i=0; i<a.length; i++) if (a[i] < 0) a[i] = -a[i]; } }

Para usar uma classe em que nenhum mtodo sincronizado num ambiente de mltiplos threads pode-se criar uma classe estendida (subclasse) e reescrever os mtodos que se pretendem que sejam sincronizados declarando-os sincronizados com chamadas aos respectivos mtodos da superclasse atravs da palavra-chave super.

DEI - ISEP

Fernando Mouta

Você também pode gostar