Entendendo Generics no Java
Foto de Luis P.
Por: Luis P.
14 de Janeiro de 2025

Entendendo Generics no Java

Tipos Parametrizados para Maior Flexibilidade

Java Generics

Os Generics foram introduzidos no Java 5 para permitir que classes, interfaces e métodos trabalhem com tipos parametrizados. Essa funcionalidade aumenta a segurança e a reutilização do código, reduzindo a necessidade de conversões explícitas e evitando erros em tempo de execução.

Neste artigo, exploraremos o conceito de Generics, como utilizá-los e como eles tornam o código mais robusto e flexível.


Por Que Usar Generics?

Antes dos Generics, os desenvolvedores usavam coleções que armazenavam objetos como Object. Isso exigia type casting ao recuperar elementos, o que era propenso a erros:

Sem Generics:

List lista = new ArrayList();
lista.add("Texto");
String s = (String) lista.get(0); // Casting necessário

Se um tipo incompatível fosse adicionado à lista, isso causaria um erro em tempo de execução:

lista.add(123); // Compila, mas lança ClassCastException ao recuperar

Com Generics, o tipo é definido na declaração, eliminando a necessidade de casts explícitos e aumentando a segurança:

Com Generics:

List<String> lista = new ArrayList<>();
lista.add("Texto");
String s = lista.get(0); // Sem casting

Como Funciona o Generics

Os Generics funcionam parametrizando o tipo em tempo de compilação. Isso significa que você pode especificar o tipo ao criar uma classe, interface ou método genérico.

Exemplo de Classe Genérica

public class Caixa<T> {
    private T objeto;

    public void set(T objeto) {
        this.objeto = objeto;
    }

    public T get() {
        return objeto;
    }
}

public class Main {
    public static void main(String[] args) {
        Caixa<String> caixa = new Caixa<>();
        caixa.set("Olá, Generics!");
        System.out.println(caixa.get()); // Saída: Olá, Generics!
    }
}

Interface Genérica

public interface Comparador<T> {
    int comparar(T o1, T o2);
}

public class ComparadorString implements Comparador<String> {
    @Override
    public int comparar(String o1, String o2) {
        return o1.compareTo(o2);
    }
}

Métodos Genéricos

Você também pode criar métodos genéricos que funcionam com diferentes tipos, sem precisar parametrizar a classe inteira.

Exemplo:

public class Util {
    public static <T> void imprimirArray(T[] array) {
        for (T elemento : array) {
            System.out.println(elemento);
        }
    }

    public static void main(String[] args) {
        Integer[] numeros = {1, 2, 3};
        String[] palavras = {"A", "B", "C"};

        Util.imprimirArray(numeros);
        Util.imprimirArray(palavras);
    }
}

Wildcards (Curingas)

O wildcard (?) é usado quando você não sabe ou não precisa especificar o tipo exato em um parâmetro genérico.

Tipos de Wildcards

  1. Unbounded Wildcard (?): Aceita qualquer tipo.

    public void imprimirLista(List<?> lista) {
        for (Object elemento : lista) {
            System.out.println(elemento);
        }
    }
    
  2. Upper Bounded Wildcard (<? extends T>): Permite tipos que são subtipos de T.

    public void imprimirNumeros(List<? extends Number> numeros) {
        for (Number numero : numeros) {
            System.out.println(numero);
        }
    }
    
  3. Lower Bounded Wildcard (<? super T>): Permite tipos que são supertipos de T.

    public void adicionarElemento(List<? super Integer> lista) {
        lista.add(123);
    }
    

Restrições e Limitações

  1. Tipos Primitivos: Generics não funcionam diretamente com tipos primitivos como int ou double. Use as classes wrapper (Integer, Double) em vez disso.

    List<Integer> lista = new ArrayList<>();
    
  2. Erasure (Apagamento de Tipos): Durante a compilação, os tipos genéricos são apagados e substituídos por Object. Isso significa que:

    • Não é possível instanciar arrays de tipos genéricos.
    • Não há sobrecarga de métodos com base em tipos genéricos.

Benefícios dos Generics

  1. Segurança de Tipo: Reduz erros de ClassCastException em tempo de execução.
  2. Reutilização de Código: Permite criar classes e métodos que funcionam para diferentes tipos.
  3. Legibilidade: Torna o código mais claro, especificando explicitamente os tipos esperados.

Os Generics tornam o Java mais seguro e flexível, permitindo que desenvolvedores criem código reutilizável e menos propenso a erros. Ao entender como funcionam e explorar seus recursos, você pode melhorar a qualidade e a robustez de seus projetos. Experimente implementar Generics em suas classes e métodos para descobrir o quanto eles podem simplificar e aprimorar seu código!

Luis P.
Luis P.
Boa Ventura / PB
Responde em 3 min
Identidade verificada
1ª hora grátis
5,0
nota média
1
avaliação
R$ 40
por hora
Graduação: Licenciatura em Computação (UEPB - Universidade Estadual da Paraíba)
Java - Springboot, Java para Web, Testes em Java
Professor de informática, português e inglês. Formado em computação e letras inglês/português. Servidor público aprovado em 3 concursos.

Confira artigos similares

Aprenda sobre qualquer assunto