Orientação a Objetos – Começões de objetos
Programação 2 –
Aulas 8 e 9
Apresentar o conceito de uma coleção de objetos
Caracterizar o comportamento de uma coleção
Ver como iteração numa coleção usando índices
Entender a necessidade de cast
Ver como iteração numa coleção usando um iterador
Pesquisa em coleções
O que é uma coleção: apresentando o saco de objetos
Nós somos clientes (usuários) da coleção: o que queremos fazer com ela?
Nem sempre queremos fazer as mesmas coisas, mas as possibilidades úteis são:
◦ Adicionar um objeto dentro da coleção
◦ Remover um objeto da coleção
◦ Pesquisar (achar a referência a) um objeto particular da coleção, dada uma chave
◦ Iterar (ou varrer) os objetos da coleção
i) Isso significa fazer um loop tratando de cada objeto da coleção, um de cada vez
Nem toda coleção permite todas as operações acima
O programa Cartas5.java mostra que Baralho é uma coleção
◦ Contém outros objetos (Cartas)
◦ Porém, é uma coleção peculiar, porque:
i) Já vem cheia de objetos
ii)Não tem método para adicionar Carta
iii) O método pegaCarta() permite fazer uma iteração dos objetos, conjuntamente com a remoção dos objetos
Normalmente, queremos coleções com comportamento mais completo
O saco de objetos não poderia ser um array?
Sim, como mostra o programa Cadastro1.java a seguir
package p2.exemplos; /* * Uso de arrays */ import java.util.Arrays; import p1.io.Entrada; public class
Cadastro1 { public final
int MAX_PESSOAS
= 10; private final
String prompt = "Digite
o nome de uma pessoa: "; private String[] cadastro = new String[MAX_PESSOAS]; private int numPessoas; public void
cadastraPessoas() { String nome; while ((nome = Entrada.in.lerLinha(prompt))
!= null) { cadastro[numPessoas++] = nome; } } public void
imprimeCadastro() { System.out.println(); for (int
i = 0; i < numPessoas; i++) { System.out.println(cadastro[i]); } } public String[] ordenaCadastro() { String[] cadOrdenado = new String[numPessoas]; for (int
i = 0; i < numPessoas; i++) { cadOrdenado[i] = cadastro[i]; } Arrays.sort(cadOrdenado); return cadOrdenado; } public static void imprimeCadastro(String[]
cadastro) { System.out.println(); for (int
i = 0; i < cadastro.length; i++) { System.out.println(cadastro[i]); } } public static void
main(String[] args) { Cadastro1 cadastro = new Cadastro1(); //
entrada dos dados de cadastro cadastro.cadastraPessoas(); //
imprime o cadastro antes da ordenação cadastro.imprimeCadastro(); //
ordena o cadastro String[] cadOrdenado =
cadastro.ordenaCadastro(); Cadastro1.imprimeCadastro(cadOrdenado); } //
main }
// Cadastro1 |
A saída do programa
Digite
o nome de uma pessoa: Raquel Digite
o nome de uma pessoa: Jacques Digite
o nome de uma pessoa: Ana Digite
o nome de uma pessoa: Fubica Digite
o nome de uma pessoa: Nazareno Digite
o nome de uma pessoa: Livia Digite
o nome de uma pessoa: ^z Raquel Jacques Ana Fubica Nazareno Livia Ana Fubica Jacques Livia Nazareno Raquel |
Observe que ^z (Ctrl+z) é a forma de indicar fim de arquivo no teclado
Tente rodar o programa tendo o cadastro pronto num arquivo de texto (para casa)
java -classpath
.;packagep1\p1.jar Cadastro1 < cadastro.txt |
Por que não ordenamos o próprio cadastro?
Pergunta: Usando um array como coleção, como implementar as 4 operações?
◦ Adicionar
◦ Remover
◦ Pesquisar
◦ Iterar
O que ocorre se digitar mais do que 10 nomes na entrada?
◦ Tente!
Como solucionar?
◦ Ver Cadastro2.java
Existem arrays que crescem automaticamente?
◦ Java tem várias coleções que fazem isso
Um exemplo é a coleção ArrayList que se comporta como um array que ajusta seu tamanho
◦ Ver o programa Cadastro3.java a seguir
package p2.exemplos; /* * Cadastro com ArrayList em vez de array. * Mostra como ArrayList é essencialmente um
array que cresce sob demanda. * Introdução ao uso de List e ArrayList. */ import java.util.*; import p1.io.Entrada; public class
Cadastro3 { private final
String prompt = "Digite
o nome de uma pessoa: "; private List<String> cadastro = new ArrayList<String>(); public static void main(String[]
args) { Cadastro3 cadastro = new Cadastro3(); //
entrada dos dados de cadastro cadastro.cadastraPessoas(); //
imprime o cadastro antes da ordenação cadastro.imprimeCadastro(); //
ordena o cadastro String[] cadOrdenado =
cadastro.ordenaCadastro(); Cadastro3.imprimeCadastro(cadOrdenado); } //
main public void
cadastraPessoas() { String nome; while ((nome = Entrada.in.lerLinha(prompt))
!= null) { cadastro.add(nome); } } public void
imprimeCadastro() { System.out.println(); for (int
i = 0; i < cadastro.size(); i++) { System.out.println(cadastro.get(i)); } } public String[] ordenaCadastro() { String[] cadOrdenado = new String[cadastro.size()]; for (int
i = 0; i < cadastro.size(); i++) { cadOrdenado[i] = cadastro.get(i); } Arrays.sort(cadOrdenado); return cadOrdenado; } public static void
imprimeCadastro(String[] cadastro) { System.out.println(); for (int
i = 0; i < cadastro.length; i++) { System.out.println(cadastro[i]); } } }
// Cadastro3 |
Observe a declaração de cadastro
◦ O tipo genérico é List
◦ O objeto que criamos é da classe ArrayList
◦ ArrayList "é uma" List
◦ Tem outros tipos de objetos que se comportam como List
◦ Falaremos disso mais na frente quando falarmos de interfaces
Observações sobre ArrayList
◦ Qualquer objeto pode ser colocado dentro de um ArrayList
◦ Aqui, colocamos objetos do tipo String
i) Usamos generics para verificar em tempo de compilação que apenas objetos do tipo String serão realmente manipulados
(1) Garante que a coleção será de um tipo específico
(2) Por isso usamos <String>
(3) Evita conversões de tipo (transformações explícitas) repetitivas no código
(4) Diminui probabilidade de surpresas indesejáveis em tempo de execução
◦ O número de objetos no ArrayList é size()
◦ Para acessar o i-ésimo elemento de um ArrayList, use get(i)
Tem outra forma de iterar uma coleção sem usar índices
Usando um "iterador", podemos dizer: "me dê o próximo, me dê o próximo, me dê o próximo, ..." até acabar
O primeiro exemplo usa um ArrayList
Ver a solução em Cartas6.java
package p2.exemplos; /* * Exemplo do uso de um iterador e uma lista */ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import p1.aplic.cartas.Baralho; import p1.aplic.cartas.Carta; import p1.io.Entrada; public class Cartas6 { public static void main(String[]
args) { Baralho baralho = new Baralho(); baralho.baralhar(); //
List é uma "Coleção" de objetos genéricos List<Carta> aMao = new ArrayList<Carta>(); encheMao(baralho, aMao); //
iteraNaMao server para varrer (iterar) as cartas na mao Carta maiorCarta = iteraNaMao(aMao); //
List tem um toString bonitinho também! :-) System.out.println("A mao: " + aMao); System.out.println("A maior carta: " + (maiorCarta == null ? "nao
tem" :
maiorCarta)); } private static Carta iteraNaMao(List<Carta> aMao) { Iterator<Carta> iteraNaMao =
aMao.iterator(); Carta maiorCarta = null; while (iteraNaMao.hasNext()) { Carta proximaCarta =
iteraNaMao.next(); if (maiorCarta == null || proximaCarta.compareTo(maiorCarta) > 0) { maiorCarta = proximaCarta; } } return maiorCarta; } private static void
encheMao(Baralho baralho, List<Carta> aMao) { int n = Entrada.in.lerInt("Quantas cartas na mao? "); for (int
i = 0; i < n; i++) { aMao.add(baralho.pegaCarta()); } } } |
A saída do programa é:
Quantas cartas na mao? 4 A mao: [VALETE de ESPADAS, AS de
PAUS, QUATRO de COPAS, SETE de COPAS] A maior carta: VALETE de ESPADAS |
Iteradores são objetos que nos permitem varrer coleções, sem a preocupação com a representação interna da coleção
◦ Veja quantas implementações diferentes existem de classes que representam coleções
É um padrão de projeto que permite ocultação de informação
Veja exemplo de sua importância no código abaixo:
package p2.exemplos; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.TreeSet; public class
CrossContainerIteration { private HashMap<String, String> hmap; private ArrayList<String> array; private TreeSet<String> tset; public CrossContainerIteration() { hmap = new HashMap<String, String>(); array = new ArrayList<String>(); tset = new TreeSet<String>(); povoaColecoes(); } private void
povoaColecoes() { String[] conteudo = { "Raquel", "Camila" }; for (String nome : conteudo) { hmap.put(nome, "hmap:" + nome); array.add("array:" + nome); tset.add("tset:" + nome); } } public void display(Iterator<String> it) { System.out.println("display"); System.out.print("[
"); while (it.hasNext()) { System.out.print(it.next()
+ " "); } System.out.println("]"); } public void displayNumLetras(Iterator<String> it) { System.out.println("displayNumLetras"); System.out.print("[
"); while (it.hasNext()) { System.out.print(it.next().length()
+ " "); } System.out.println("]"); } public HashMap<String, String> getHmap()
{ return hmap; } public ArrayList<String> getArray() { return array; } public TreeSet<String> getTset() { return tset; } public void imprimeNumLetrasArray() { System.out.println("imprimeNumLetrasArray"); System.out.print("[ "); for (int i = 0; i <
array.size(); i++) { System.out.print(array.get(i).length()+
" "); } System.out.println("]"); } public void imprimeNumLetrasHmap() { System.out.println("imprimeNumLetrasHmap"); System.out.print("[
"); Collection<String>
col = hmap.values(); for (String nome : col) { System.out.print(nome.length()
+ " "); } System.out.println("]"); } public void imprimeNumLetrasSet() { System.out.println("imprimeNumLetrasSet"); Object[]
col = tset.toArray(); System.out.print("[
"); for (int i = 0; i <
col.length; i++) { System.out.print(((String)col[i]).length()
+ " "); } System.out.println("]"); } public static void main(String[]
args) { CrossContainerIteration
cross = new CrossContainerIteration(); cross.display(cross.getArray().iterator()); cross.display(cross.getHmap().values().iterator()); cross.display(cross.getTset().iterator()); cross.imprimeNumLetrasArray(); cross.imprimeNumLetrasHmap(); cross.imprimeNumLetrasSet(); cross.displayNumLetras(cross.getArray().iterator()); cross.displayNumLetras(cross.getHmap().values().iterator()); cross.displayNumLetras(cross.getTset().iterator()); } } |
package p2.exemplos; /* * Laços aninhados */ import java.util.ArrayList; import java.util.List; import p1.aplic.geral.Pessoa; import p1.io.Entrada; public class
Pesquisa1 { public static void main(String[] args) { List<Pessoa> cadastro = new ArrayList<Pessoa>(); povoaCadastro(cadastro); pesquisaPorCPF(cadastro); } //
main private static void
povoaCadastro(List<Pessoa> cadastro) { final String PROMPT1 = "Digite
o nome de uma pessoa (\"fim\" para terminar): "; final String PROMPT2 = "Digite
o CPF dessa pessoa: "; String nome; String cpf; //
entrada dos dados de cadastro while ((nome = Entrada.in.lerLinha(PROMPT1))
!= null && !nome.equals("fim"))
{ cpf = Entrada.in.lerLinha(PROMPT2); if (cpf != null) { cadastro.add(new Pessoa(nome, cpf)); } } //
while } private static void
pesquisaPorCPF(List<Pessoa> cadastro) { final String PROMPT3 = "Digite
o CPF a pesquisar (\"fim\" para terminar): "; String cpf; //
pesquisa de dados por cpf //
observe o aninhamento de laços //
Seria possivel usar o método indexOf de List, mas //
queremos mostrar como fazer pesquisa sequencial num array while ((cpf = Entrada.in.lerLinha(PROMPT3)) != null &&
!cpf.equals("fim")) { boolean achei = false; for (int
i = 0; i < cadastro.size(); i++) { Pessoa p = cadastro.get(i); if (p.getCPF().equals(cpf)) { System.out.println(p.getNome()); achei
= true; } }
// for if (!achei) { System.out.println("Nao achei CPF " + cpf + "
no cadastro."); } } //
while } } // Pesquisa1 |
Saída do programa:
Digite o nome de uma
pessoa ("fim" para terminar): raquel Digite o CPF dessa
pessoa: 123456 Digite o nome de uma
pessoa ("fim" para terminar): camila Digite o CPF dessa
pessoa: 234567 Digite o nome de uma
pessoa ("fim" para terminar): felipe Digite o CPF dessa
pessoa: 345678 Digite o nome de uma
pessoa ("fim" para terminar): rodrigo Digite o CPF dessa
pessoa: 45678 Digite o nome de uma
pessoa ("fim" para terminar): fim Digite o CPF a
pesquisar ("fim" para terminar): 234567 camila Digite o CPF a
pesquisar ("fim" para terminar): 4567 Nao achei CPF 4567 no
cadastro. Digite o CPF a
pesquisar ("fim" para terminar): fim |
Veja como incluir um " dentro de um string: usando \"
Que coleção estamos usando? Para quê?
Objetos de qual classe são colocados na coleção?
Também estamos vendo um exemplo de loops aninhados
Há coleções melhores do que List para fazer pesquisa
◦ Veremos isso mais daqui a pouco
◦ Exercício: refaça o programa de pesquisa acima usando um Map
Vamos agora ver um exemplo dos comandos “break” para sair de um loop e “continue” para passar para a próxima iteração do loop
package p2.exemplos; //
Programa feio e sem utilidade, para demonstrar uso de break e continue public class
BreakEContinue { public static void main(String[]
args) { // imprime os numeros entre 0 e 78 que sao
multiplos de 9 for (int i = 0; i <
100; i++) { if (i == 78) break; // sai do loop for if (i % 9 != 0) continue; // volta
para o inicio do loop for System.out.print(i + "
"); } System.out.println(); // imprime todos os multiplos menores que 78, de
4, de 5... até 9 for (int i = 4; i <
10; i++) { int j = 0; while (j++ < 100) { if (j == 78) break; // sai do loop while if (j % i != 0) continue; // volta
para o inicio do loop while System.out.print(j + "
"); } System.out.println(); } } } |
A saída do programa é
Multiplos de 9 9 18 27 36 45 54 63 72 Multiplos de 4 4 8 12 16 20 24 28 32
36 40 44 48 52 56 60 64 68 72 76 Multiplos de 5 5 10 15 20 25 30 35 40
45 50 55 60 65 70 75 Multiplos de 6 6 12 18 24 30 36 42 48
54 60 66 72 Multiplos de 7 7 14 21 28 35 42 49 56
63 70 77 Multiplos de 8 8 16 24 32 40 48 56 64
72 Multiplos de 9 9 18 27 36 45 54 63 72 |
Como usar break e continue para melhorar o programa Pesquisa1 de forma a:
◦ Desconsiderar comentários, isto é, linhas que começam com #
◦ Terminar o loop de pesquisa tão logo a pessoa com CPF a ser pesquisado for encontrada
Veja o programa a seguir
package p2.exemplos; /* * Uso de break e continue * Cadastro onde linha iniciando com # são
comentários * Pesquisa em que o loop de pesquisa é
encerrado tão logo o elemento * procurado seja encontrado */ import java.util.ArrayList; import java.util.List; import p1.aplic.geral.Pessoa; import p1.io.Entrada; public class Pesquisa2 { public static void main(String[]
args) { final String prompt1 = "Digite
o nome de uma pessoa (\"fim\" para terminar): "; final String prompt2 = "Digite
o CPF dessa pessoa: "; final String prompt3 = "Digite
o CPF a pesquisar (\"fim\" para terminar): "; final String INICIO_COMENTÁRIO = "#"; String nome; String cpf; List<Pessoa> cadastro = new ArrayList<Pessoa>(); //
entrada dos dados de cadastro while ((nome = Entrada.in.lerLinha(prompt1))
!= null && !nome.equals("fim"))
{ if (nome.startsWith(INICIO_COMENTÁRIO)) { continue; } //
agora, processa informação de verdade cpf = Entrada.in.lerLinha(prompt2); if (cpf != null) { cadastro.add(new Pessoa(nome, cpf)); } } //
while //
pesquisa de dados por cpf //
observe o aninhamento de laços //
Seria possivel usar o método indexOf de List, mas //
queremos mostrar como fazer pesquisa sequencial numa List while ((cpf = Entrada.in.lerLinha(prompt3))
!= null && !cpf.equals("fim"))
{ Pessoa p = null; for (int i = 0; i <
cadastro.size(); i++) { p
= cadastro.get(i); if (p.getCPF().equals(cpf)) { System.out.println(p.getNome()); break; // cai fora
do laço de pesquisa } }
// for if (p == null || !p.getCPF().equals(cpf)) { System.out.println("Nao achei CPF " + cpf + "
no cadastro."); } } //
while } //
main } // Pesquisa2 |