Generics em Java: para que servem e como usar na prática

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: O problema que os Generics resolvem

Imagine que você está escrevendo um método para ordenar uma lista de números. Você o escreve para Integer e, uma semana depois, precisa ordenar uma lista de String. É necessário criar um novo método ou usar Object e fazer conversões de tipo constantemente. Isso é inconveniente, inseguro e leva a erros em tempo de execução.

É exatamente esse problema que os Generics (genéricos) resolvem em Java. Eles permitem criar classes, interfaces e métodos que trabalham com diferentes tipos de dados, mas mantêm a tipagem estrita em tempo de compilação. Sem os genéricos, o Java moderno seria muito menos conveniente e seguro.

Neste artigo, vamos abordar para que servem os Generics, como eles funcionam e, o mais importante, como aplicá-los em exemplos reais.



1. Fundamentos dos Generics: o que são e como funcionam

1.1. O problema dos tipos "brutos" (raw types)

Antes do Java 5 (2004), os desenvolvedores usavam coleções sem especificar o tipo:

List list = new ArrayList();list.add("Hello");list.add(123);// Ao recuperar, é preciso lembrar qual tipo está armazenadoString text = (String) list.get(0); // OKInteger num = (Integer) list.get(1); // OK// Mas se errar — ClassCastException em runtimeString error = (String) list.get(1); // Erro!

Esse código é perigoso: o erro só é descoberto quando o programa é executado.



1.2. Como os Generics funcionam

Os Generics permitem especificar o tipo de dados com o qual uma classe ou método irá trabalhar, diretamente nos colchetes angulares <T>. O compilador verifica os tipos em tempo de compilação e insere automaticamente as conversões corretas.

Sintaxe básica:

// Declaração de uma classe genéricapublic class Box<T> {    private T content;        public void setContent(T content) {        this.content = content;    }        public T getContent() {        return content;    }}

// UsoBox<String> stringBox = new Box<>(); // <> — operador diamond (Java 7+)stringBox.setContent("Olá");String text = stringBox.getContent(); // Sem conversão!

Box<Integer> intBox = new Box<>();intBox.setContent(42);int number = intBox.getContent(); // Sem conversão!

// stringBox.setContent(123); // Erro de compilação!


1.3. Vantagens na prática

  • Segurança de tipos: erros são detectados em tempo de compilação, não em runtime.
  • Eliminação de conversões explícitas: o código fica mais limpo e legível.
  • Reutilização de código: uma classe/método funciona com qualquer tipo.


2. Generics na prática: classes, métodos e interfaces

2.1. Classes genéricas

O caso mais comum são as coleções. Mas você pode criar suas próprias classes genéricas:

public class Pair<K, V> {    private K key;    private V value;        public Pair(K key, V value) {        this.key = key;        this.value = value;    }        public K getKey() { return key; }    public V getValue() { return value; }}

// UsoPair<String, Integer> pair = new Pair<>("Idade", 30);String key = pair.getKey();Integer value = pair.getValue();


2.2. Métodos genéricos

Um método pode ter seus próprios parâmetros de tipo, não relacionados à classe:

public class Utils {    // Método genérico para criar uma lista a partir de um array    public static <T> List<T> arrayToList(T[] array) {        List<T> list = new ArrayList<>();        for (T element : array) {            list.add(element);        }        return list;    }}

// UsoString[] names = {"Ana", "Bruno", "Carlos"};List<String> nameList = Utils.arrayToList(names);


2.3. Interfaces genéricas e

Blogs

Book Recommendations