Orientação a Objetos – Começões de objetos

Programação 2 – Aulas 8 e 9

Objetivos da seção

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

Coleções de Objetos: Iteração Usando Índices

O que é uma coleção: apresentando o saco de objetos

                                                          MCj04316090000[1]

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 Array como Coleção

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)

Coleções de Objetos: Iteração Usando um Iterador

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());

   }

}

Coleções de Objetos: Pesquisa

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

Os Comandos break e continue

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

 

ProgramaHP da disciplina