Generics em Java: escrevendo código flexível sem (ClassCastException)

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

Genéricos em Java: como parar de ter medo de colchetes angulares e começar a escrever código confiável

\n\n

No mundo Java, há uma coisa que assusta os iniciantes quase mais do que a concorrência — são os colchetes angulares <>. Generics (também conhecidos como genéricos ou generalizações) parecem misteriosos, mas na verdade são seu principal aliado na luta por um código limpo e seguro. Vamos entender como funciona a tipagem em Java com exemplos que você pode aplicar hoje mesmo.

\n\n

Imagine: você está escrevendo um método que deve funcionar com números, strings e suas próprias classes. Sem genéricos, você teria que criar dezenas de métodos sobrecarregados ou usar Object e verificar tipos manualmente constantemente. As generalizações Java resolvem esse problema de forma elegante e segura.

\n\n

Por que sem genéricos o código se transforma em um campo minado?

\n\n

Vamos lembrar como os programadores viviam antes do surgimento dos generics (antes do Java 5). Se você já escreveu um ArrayList sem especificar o tipo, conhece esse pesadelo:

\n\n
List list = new ArrayList();\nlist.add("Olá");\nlist.add(42);\nlist.add(new Object());\n\n// Em algum lugar após 100 linhas de código:\nString text = (String) list.get(1); // ClassCastException em tempo de execução!
\n\n

O problema clássico: ClassCastException — um erro que aparece apenas durante a execução. Você poderia passar a lista para outro método, e alguém lá está certo de que ela contém apenas strings. E bum! O aplicativo quebra. Os genéricos em Java transferem a verificação de tipos para o tempo de compilação — é como um seguro que funciona antes de você pegar o volante.

\n\n

Generics em Java: sintaxe básica que você precisa saber

\n\n

Na base dos genéricos está uma ideia simples: parametrizamos uma classe ou método com um tipo. Em vez de um tipo concreto, escrevemos um parâmetro de tipo (geralmente uma letra maiúscula: T, E, K, V).

\n\n

O exemplo mais popular são as coleções Java:

\n\n
// Sem genérico — perigoso\nList rawList = new ArrayList();\n\n// Com genérico — seguro\nList<String> safeList = new ArrayList<>();\nsafeList.add("Java");\nsafeList.add("Generics");\n// safeList.add(123); // Erro de compilação!
\n\n

O compilador agora sabe: dentro de safeList só podem haver strings. Tentar adicionar um número causará um erro em tempo de compilação, não em tempo de execução. Isso é a segurança de tipos Java em ação.

\n\n

Criando sua primeira classe genérica

\n\n

Suponha que estamos escrevendo um contêiner simples para armazenar um valor. Sem genéricos, teríamos que usar Object:

\n\n
public class Box {\n    private Object value;\n\n    public void set(Object value) { this.value = value; }\n    public Object get() { return value; }\n}
\n\n

Agora — com genérico:

\n\n
public class Box<T> {\n    private T value;\n\n    public void set(T value) { this.value = value; }\n    public T get() { return value; }\n}\n\n// Uso:\nBox<Integer> intBox = new Box<>();\nintBox.set(100);\nint value = intBox.get(); // Sem cast!
\n\n

Observe: não precisamos mais escrever (Integer) intBox.get(). O compilador sabe que get() retornará Integer. Essa é a magia das generalizações Java.

\n\n

Tipagem em Java: restrições e wildcards

\n\n

Os genéricos seriam muito simples se não houvesse nuances. A principal delas são os bounded type parameters (parâmetros de tipo limitados). Às vezes, precisamos dizer: "O tipo T deve ser um número" ou "T deve implementar a interface Comparable".

\n\n
// T só pode ser Number ou suas subclasses\npublic class Calculator<T extends Number> {\n    private T value;\n\n    public double square() {\n        return value.doub                

Blogs

Book Recommendations