Utilizando Generics em Java

Este artigo é a primeira parte de uma série de tutoriais de Generics em Java, vamos analisar seu uso básico com estrutura de coleção, que é o caso mais comum de uso de Generics.

Em partes posteriores do tutorial, você aprenderá tópicos avançados como como criar suas próprias classes Generics em Java.

Generics em Java

O que é Generics

Generics é um mecanismo poderoso que resulta em um código mais limpo, robusto e fácil de entender. Os genéricos permitem ligar classes e objetos a certos tipos. O uso mais comum dos genéricos é com classes de coleção como ArrayList, HashMap, etc.

Se você aprendeu programação Java após a versão Java 5 ou 6, então você já pode estar usando genéricos e não sabe sobre isso. Se você escreveu este tipo de código, então é possível que você já esteja usando Generics.

ArrayList<String> nomes = new ArrayList<String>();

A parte <String> é uma sintaxe genérica. Se você não está familiarizado com isso, então veremos o que ela significa e que vantagens ela oferece.

Collections Framework

Para entender Generics, é ideal conhecer Collections. Se você não está familiarizado com o framework de coleções em Java, se trata de um conjunto de Interfaces e Classes na API Java.

Estas classes fornecem a capacidade de armazenar múltiplos valores como arrays, mas ao contrário dos arrays, o tamanho das coleções pode mudar se mais elementos forem adicionados a elas. As classes de coleções também fornecem a capacidade de armazenar pares de valores chave.

Segurança ao informar o Type nas Collections

O uso de Generics proporciona segurança na digitação enquanto usa Collections. Desta forma, temos segurança para evitar exceções de tempo de execução ao encontrar erros durante a compilação.

Um exemplo que mostra bem este problema é o código abaixo. Em seguida, veremos como os Generics o resolvem.

Ete código cria uma List e adiciona alguns elementos à lista. Depois, recupera os elementos da lista para obter seu total.

List numeros = new ArrayList();  //raw or untyped list
numeros.add(10);
numeros.add("20");
int total = 0;
for(int i = 0; i < numeros.size(); i++) {
    Integer numero = (Integer)numeros.get(i);
    total += numero.intValue();
}

Observe abaixo que, durante a compilação, nenhum erro foi encontrado. No entanto, quando o programa dá continuidade na execução do código, a JVM retorna um ClassCastExceptioncomo resultado.

Generics em Java

Isto acontece pois o segundo elemento da Lista é uma String, então quando o código tenta digitar para o Integer, então a JVM lança essa exceção.

Porém, com o uso de Generics você terá garantia que isso não irá acontecer. Durante a compilação, o problema será sinalizado ao invés de uma exceção em tempo de execução. Vamos ver como o código fica com Generics.

List<Integer> numbers = new ArrayList<Integer>();  //typed list
numbers.add(10);
number.add("20");  //erro em tempo de compilação
int total = 0;
for(int i = 0; i < numbers.size(); i++) {
    Integer number = numbers.get(i); //type-cast denecessário
    total += number.intValue();
}

Desta vez, o compilador entende que a lista de números só pode conter elementos do tipo Integer. Então, quando você tenta adicionar uma String a esta lista o compilador irá reportar esse erro. Além disso, como você deve ter notado, você não precisa de um type-cast quando você obtém um elemento da lista na linha no. 6. Isto porque o compilador também sabe que os elementos da lista em números são do tipo Integer e, assim, o type-cast é feito de forma automática durante a compilação.

Lista não “tipada” x Generics

Com uma Lista não “tipada”, você pode adicionar qualquer tipo de elemento à lista, e o compilador não reclamará sobre isso. Entretanto, com Generics, o compilador só permite adicionar objetos do tipo que você usou ao criar a lista. Vamos ver um exemplo simples:

List untypedList = new ArrayList();
//qualquer tipo de objeto pode ser adicionado à lista
untypedList.add("Hello World");
untypedList.add(123);
List<String> stringList = new ArrayList<String>();
//somente objetos String podem ser adicionados
stringList.add("Hello World");
stringList.add(123);  //erro durante a compliação

O código acima demonstra que com listas não “tipadas”, o programador tem que garantir que está adicionando o tipo certo de objetos a uma Lista. Se um elemento errado for adicionado à Lista, você pode obter uma ClassCastException enquanto recupera elementos da Lista. Contudo, com Generics, o compilador se encarrega disso, como na linha não. 8 onde foi adicionado um objeto Integer a uma Lista que leva apenas objetos String. O compilador desautorizaria isso tornando sua vida mais fácil.

Usando Generics

O uso de Generics torna o seu código mais legível e evita a adição acidental de objetos errados a uma coleção. Como digamos que você estava escrevendo um pedaço de código que pegou uma Lista de objetos de classe Cliente e preparou duas listas de nomes de empregados (objetos String) e ids (objetos Long). Aqui está o código sem os genéricos:

class Cliente {
    private String nome;
    private Long codigo;
    public String getNome() {
        return nome;
    }
    public Long getCodigo() {
        return codigo;
    }
    // setters
}
..
public void gerenciarClientes(List clientes) {
    List cliNomes = new ArrayList();  //raw list
    List cliCodigos = new ArrayList();    //raw list
    for(int i = 0; i < clientes.size(); i++) {
        Cliente cliente = (Cliente)clientes;
        empNames.add(cliente.getNome());
        cliCodigos.add(cliente.getNome());  //preste atenção nesta linha
    }
 	...
}

Tudo está ok com este código, no entanto, foi adicionado acidentalmente adicionei nomes de clientes à lista de identificação. Por isso, será obtida uma exception em tempo de execução quando tentar usar a informação armazenada na lista cliCodigos, pois o sistema estará esperando um objeto Long, mas será retornado um objeto String. Com o uso de Generics, o compilador teria identificado isso.

Agora, vamos ver uma versão deste código com Generics:

..
public void gerenciarClientes(List clientes) {
    List<String> cliNomes = new ArrayList<String>();  //raw list
    List<Long> cliCodigos = new ArrayList<Long>();    //raw list
    for(int i = 0; i < clientes.size(); i++) {
        Cliente cliente = (Cliente)clientes;
        empNames.add(cliente.getNome());
        cliCodigos.add(cliente.getNome());  //erro na compilação
    }
	...
}

Neste código, o compilador vai identificar um erro na linha n. 7 que não é possível adicionar um objeto String a uma List que leva apenas objetos Long.

Conclusão

Desta forma, podemos concluir que o uso de Generics em Java não só, torna o seu código mais legível e evita a adição acidental de objetos errados a uma coleção, mas também poupa-lhe horas de depuração.

Curso de Java Para iniciantes

Que tal alavancar a sua carreira com um curso diferenciado no mercado?

Inscreva-se no curso Java para Iniciantes e aprenda o Java do zero de forma fácil, prática para impulsionar de vez sua carreira de desenvolvedor.

Se você é iniciante e nunca programou na vida e gostaria de saber como um programa de computador é criado então estas videoaulas vão te surpreender.

São 54 videoaulas explicadas nos mínimos detalhes para que qualquer pessoa possa entender independente da sua idade ou de seu conhecimento em informática.

pt_BRPortuguese
pt_BRPortuguese
%d blogueiros gostam disto: