image

Acesse bootcamps ilimitados e +650 cursos

50
%OFF
Article image

CA

Carlos Arruda01/09/2023 16:16
Compartilhe

Entendendo de vez Generics: o famigerado <T>

  • #Java

Sabemos que Java é uma linguagem de tipagem extremamente forte, isso por um lado assusta quem está começando e por outro lado nos da um controle e uma robustes muito grande do começo ao fim da criação dos programas. Um desses recursos é o uso de "generics" (genéricos), introduzidos a partir do Java 5. Generics permitem que você escreva código que pode ser reutilizado com diferentes tipos de dados, ao mesmo tempo em que mantém a segurança de tipos.

Aqui tentarei explicar de maneira mais simples o que eles resolvem, sintaxe e afins...

O Problema da Falta de Tipos Genéricos

Antes da introdução de generics, as coleções em Java (como ArrayList e HashMap) eram bastante limitadas em termos de tipos de elementos que podiam armazenar. Por exemplo, uma ArrayList só podia conter objetos do tipo "Object"(classe mais genérica da linguagem, tudo extende à classe Object), o que tornava necessário fazer conversão de tipo(cast) ao recuperar elementos da lista. Isso frequentemente levava a erros em tempo de execução e tornava o código menos seguro dando mais trabalho para criação e também para a manutenção posteriormente.

List lista = new ArrayList();
lista.add("Olá mundo"); 
String a = (String) lista.get(0); // linhas de código usando cast, sem implementação de generics. 

Introdução aos Generics

Os generics em Java foram introduzidos para resolver esse problema. Eles permitem que você escreva código que seja reutilizável e flexível, enquanto ainda mantém a segurança de tipos. Em vez de usar tipos específicos, você pode criar classes e métodos genéricos que trabalham com tipos de dados arbitrários.

Sintaxe Básica de Generics

Declaração de Classe Genérica

Para criar uma classe genérica em Java, você usa o operador diamante "<...>" após o nome da classe, seguido pelo tipo genérico ou tipos genéricos que a classe pode aceitar. Aqui está um exemplo de uma classe genérica simples:

public class Caixa<T> { 

private T conteudo;
 
public Caixa(T conteudo) { 
this.conteudo = conteudo;

 } 
public T getConteudo() { 
return conteudo;
     } 
} 

Neste exemplo, a classe Caixa pode aceitar qualquer tipo de objeto <T> O tipo <T> é um parâmetro genérico.

Uso de Classe Genérica

Agora, vamos usar a classe genérica Caixa:

Caixa<String> caixaDeString = new Caixa<>("Olá, mundo!");
String conteudo = caixaDeString.getConteúdo();
System.out.println(conteudo); // Saída: Olá, mundo! 

Neste exemplo, criamos uma instância da classe Caixa usando o tipo genérico String, isso nos dá a garantia que a classe Caixa receberá somente Objetos do tipo String.A contradição do genérics esta nessa parte, o conceito genérico se dá pelo fato de que o Dev utiliza uma classe genérica, nesse exemplo "String" para especificar o conteúdo de uma outra classe.

Benefícios dos Generics

Os generics em Java proporcionam diversos benefícios:

  1. Segurança de Tipos: Os erros de tipo são detectados em tempo de compilação, em vez de em tempo de execução, graças aos generics. Isso torna o código mais robusto.
  2. Reutilização de Código: Você pode criar classes e métodos genéricos que funcionam com diferentes tipos de dados, promovendo a reutilização de código.
  3. Clareza e Legibilidade: O uso de generics torna o código mais claro e legível, pois elimina a necessidade de downcasting e fornece informações sobre os tipos esperados.
  4. Desempenho: Em muitos casos, os generics têm um desempenho similar ao código sem generics, pois o Java usa "erasure" (apagamento) para implementar generics.

Métodos Genéricos

Assim como as classes, você também pode criar métodos genéricos em Java. Isso permite que você escreva métodos que operam em tipos genéricos.

public <T> T obterPrimeiroElemento(List<T> lista) {
if (lista.isEmpty()) { 
    throw new NoSuchElementException("A lista está vazia.");
} 
return lista.get(0); 
} 

Neste exemplo, o método obterPrimeiroElemento() aceita uma lista de qualquer tipo genérico <T> e retorna o primeiro elemento dessa lista.

Restrições de Tipo

Às vezes, você pode querer impor restrições nos tipos genéricos que uma classe ou método pode aceitar. Isso pode ser feito usando a palavra-chave "extends"(exatamente como na herança) para especificar uma classe base ou uma interface que os tipos genéricos devem estender ou implementar.

public class Caixa<T extends Number> {
 private T conteudo; public Caixa(T conteudo) {
   this.conteudo = conteudo; 
} 

public T getConteudo() { 
return conteudo; 
 } 
} 

Neste exemplo, a classe Caixa aceita apenas tipos genéricos que estendem a classe Number.Porém isso pode ser feito com qualquer classe, tanto as nativas do JDK quanto as criadas pelo Desenvolvedor.

Wildcards (Curingas)

Em alguns casos, você pode querer escrever código genérico que seja flexível o suficiente para aceitar qualquer tipo genérico. Para isso, você pode usar wildcards (?) para representar tipos desconhecidos.

public void imprimirLista(List<?> lista) { 

for (Object item : lista) { 

  System.out.println(item);

  }
} 

Neste exemplo, o método imprimirLista aceita uma lista de qualquer tipo genérico desconhecido.Porém esse curinga deve ser usado com cuidado, somente em casos específicos, pois não faz sentido usar generics se não formos espeficicar quais tipos deverão ser usados em tais Collections.

Considerações Finais

Os generics em Java são uma poderosa ferramenta para tornar seu código mais seguro e flexível. Eles permitem que você escreva código que pode ser reutilizado com diferentes tipos de dados, ao mesmo tempo em que evita erros de tipo em tempo de execução. Ao compreender os conceitos básicos e avançados de generics, você poderá escrever código Java mais eficiente e robusto.

Espero que este artigo tenha ajudado você a entender os fundamentos dos generics em Java. Se você deseja explorar ainda mais este tópico, recomendo a leitura da documentação oficial da Oracle sobre generics em Java e a prática de escrever código usando generics para ganhar experiência. Generics são um recurso poderoso que pode melhorar significativamente a qualidade e a segurança do seu código Java.

Compartilhe
Comentários (0)