Orientação a objetos com Java Generics Byron Leite e Bruno Fernandes {byronleite,bjtf@ecomp.poli.br 1 Generics
Agenda Geral Parte 07 Exceções Parte 08 Exceções Parte 09 Classes úteis Generics Arquitetura em camadas Parte 10 Implementação de um UC na arquitetura em camadas 2 Generics
Coleções em Java Motivação Coleções tratam SEMPRE tipos genéricos (Object) É impossível, nas versões anteriores ao Java 1.5, garantir que objetos de tipos diferentes não serão inseridos em uma coleção Quando se lê objetos de uma coleção, o uso do cast é obrigatório, e sob risco de não se estar convertendo o objeto para o tipo certo 3 Generics
Problema Analisando o código abaixo... List lista = new ArrayList(); lista.add("eduardo"); // OK em compilacao lista.add(new Integer(2)); // OK em compilacao lista.add(new Double(2.2)); // OK em compilacao // Agora... // Se, mais na frente, alguem faz isso... String elemento = (String)lista.get(1); // Erro de execucao Se houvesse uma maneira de garantir em tempo de compilação que, na dada lista, só fosse possível se adicionar elementos de um mesmo tipo (suponha String)?? 4 Generics
Problema Ainda analisando o código abaixo... List lista = new ArrayList(); lista.add("eduardo"); // OK em compilacao lista.add(new Integer(2)); // OK em compilacao lista.add(new Double(2.2)); // OK em compilacao // Agora... // Se, mais na frente, alguem faz isso... String elemento = (String)lista.get(1); // Erro de execucao E, se houvesse uma maneira de evitar o cast?? Se o Java soubesse que a dada lista é uma lista de Strings, não haveria alternativa...o tipo da variável que receberia o retorno do método get TERIA que ser String 5 Generics
Solução No Java 5, é possível SUB-TIPAR alguns elementos que trabalham com tipos abstratos List<String> lista = new ArrayList<String>(); lista.add("eduardo"); // OK em compilacao lista.add(new Integer(2)); // Erro de compilacao 1 lista.add(new Double(2.2)); // Erro de compilacao 2 // Agora... // Se, mais na frente, alguem quiser acessar um elemento... String elem0 = lista.get(0); // Sem cast Integer elem1 = lista.get(1); // Erro de compilacao 3 Double elem2 = (Double)lista.get(1); // Erro de compilacao 4 O argumento entre <> é o tipo associado aos elementos que serão manipulados através dos métodos da interface List e que serão armazenados no objeto ArrayList 6 Generics
Solução É como se, colocando o tipo entre <>, o programador dissesse: Java, para esta lista que eu estou instanciando e representando por esta variável, onde antes se trabalhava com Object, passe a trabalhar APENAS com o tipo que eu especificar entre <> Este mecanismo é chamado de Generics Aumenta a garantia de código robusto e sujeito a erros de execução Diminui o uso de casts 7 Generics
Solução Nos erros de compilação 1 e 2 O método add(string s) espera uma String Está se tentando passar um Integer e um Double para uma String É o mesmo que: String s = new Integer(2); Integer não é sub-tipo de String É o mesmo que: String s = new Double(2.2); Double não é sub-tipo de String 8 Generics
Solução Nos erros de compilação 3 e 4... O tipo de retorno do método get é String Regra de compilação do cast: Tipo do cast igual ou sub-tipo do tipo da variável de destino - OK Tipo do cast e tipo da variável ou do retorno de origem na mesma hierarquia Tipo do cast: Integer Tipo do retorno de origem: String, pois o get volta uma String Integer e String não estão na mesma hierarquia 9 Generics
Percorrendo Coleções Analise o seguinte programa escrito da forma tradicional... List listaprod = new ArrayList(); long codigo = 0; do { codigo = KeyboardReader.readLong(); if (codigo > 0) { String nome = KeyboardReader.readString(); double preco = KeyboardReader.readDouble(); Produto p = new Produto(codigo,nome,preco); listaprod.add(p); while (codigo > 0); // Mostra os produtos incluidos na lista for (int i=0;i<listaprod.size();i++) { Produto p = (Produto)listaProd.get(i); System.out.println("Codigo: "+p.getcodigo()); System.out.println("Nome : "+p.getnome()); System.out.println("Preco : "+p.getpreco()); 10 Generics
Percorrendo Coleções Agora, analise o programa escrito com Generics... List<Produto> listaprod = new ArrayList<Produto>(); long codigo = 0; do { codigo = KeyboardReader.readLong(); if (codigo > 0) { String nome = KeyboardReader.readString(); double preco = KeyboardReader.readDouble(); Produto p = new Produto(codigo,nome,preco); listaprod.add(p); while (codigo > 0); // Mostra os produtos incluidos na lista //for (Produto p : listaprod) { for (int i=0;i<listaprod.size();i++) { Produto p = listaprod.get(i); System.out.println("Codigo: "+p.getcodigo()); System.out.println("Nome : "+p.getnome()); System.out.println("Preco : "+p.getpreco()); 11 Generics
Outras Aplicações Generics pode ser usado em outros contextos Garantia de compatibilidade de tipos em métodos que recebem parâmetros correlatos Rotinas genéricas podem indicar que SÓ recebem coleções de uma SUB- HIERARQUIA bounded wild-cards 12 Generics
Generics em Classes e Intefaces Parametrizam a classe ou interface public interface List<T> extends Collection<T> {... T get(int index);... Método genérico: public static <T> T getfirst(list<t> list) { return list.get(0); 13 Generics
Wildcards Permite um tratamento mais genérico dos tipos passados a uma função public void processelements(list<?> elements) { for(object o : elements) { System.out.println(o); /* Podemos atribuir um list de qualquer tipo a nosso método, pois ele tem um tipo desconhecido/genérico */ List<A> lista = new ArrayList<A>(); processelements(lista); 14 Generics
Extends Wildcards public void processelements(list<? extends Fruit> elements) { for(fruit a : elements) { System.out.println(a.getValue()); /* Podemos agorar passar nossas frutas diversas ao método processelements */ List<Apple> listapple = new ArrayList<Apple>(); processelements(listapple); List<Orange> listorange = new ArrayList<Orange>(); processelements(listorange); List<Strawberry> liststrawberry = new ArrayList<Strawberry>(); processelements(liststrawberry); 15 Generics