Generics em Java: para que servem e como usar
Generics (genéricos) — um dos principais recursos do Java, introduzido na versão J2SE 5.0. Eles permitem criar classes, interfaces e métodos que trabalham com tipos de dados especificados no momento da chamada. Em vez de escrever implementações separadas para Integer, String e Double, você escreve um único código universal. Neste artigo, vamos entender para que servem os Generics em Java, como usá-los na prática e quais armadilhas você deve conhecer.
Para que servem os Generics em Java?
Antes do surgimento dos Generics, os desenvolvedores usavam Object para armazenar qualquer tipo. Isso funcionava, mas gerava dois problemas sérios:
- Falta de verificação de tipos em tempo de compilação. Você podia acidentalmente colocar uma
Stringem uma lista no lugar deInteger, e o erro só aparecia durante a execução do programa. - Necessidade de conversão explícita de tipos. Cada vez que um elemento era extraído de uma coleção, era necessário um cast:
(String) list.get(0). Isso tornava o código verboso e perigoso.
Os Generics resolvem ambos os problemas. Eles permitem que o compilador verifique a correção dos tipos e realize a conversão automaticamente. Vejamos um exemplo simples:
// Sem Generics (estilo antigo)List list = new ArrayList();list.add("Hello");String s = (String) list.get(0); // conversão explícita necessária
// Com GenericsList<String> list = new ArrayList<>();list.add("Hello");String s = list.get(0); // conversão não necessáriaO código ficou mais seguro e legível. Erros de tipo são detectados em tempo de compilação, não em tempo de execução.
Como usar Generics: construções principais
1. Classes Genéricas
Você pode definir uma classe que aceita um ou mais parâmetros de tipo. Geralmente, usa-se uma letra: T (Type), E (Element), K (Key), V (Value).
public class Box<T> { private T content;
public void put(T item) { this.content = item; }
public T get() { return content; }}
// UsoBox<String> stringBox = new Box<>();stringBox.put("Java");String value = stringBox.get(); // conversão automáticaO parâmetro T é substituído pelo tipo real ao criar o objeto. O compilador garante que não é possível colocar um Integer em um Box<String>.
2. Métodos Genéricos
Métodos também podem ser genéricos, mesmo que a classe não seja. O parâmetro de tipo é especificado antes do tipo de retorno:
public class Utils { public static <T> T getMiddle(T... args) { return args[args.length / 2]; }}
// ChamadaString middle = Utils.<String>getMiddle("A", "B", "C");// ou simplesmente: Utils.getMiddle("A", "B", "C") — o compilador infere o tipoMétodos genéricos são úteis para funções utilitárias que trabalham com diferentes tipos de dados.
3. Tipos Limitados (Bounded Type Parameters)
Às vezes, é necessário restringir quais tipos podem ser usados. Por exemplo, para que um método funcione apenas com números:
public class Calculator { public static <T extends Number> double sum(T a, T b) { return a.doubleValue() + b.doubleValue(); }}
// Funciona com Integer, Double, Float, etc.double result = Calculator.sum(5, 10); // 15.0A palavra-chave extends significa que T deve ser um subtipo da classe especificada (ou implementar a interface).
Wildcards: tipos desconhecidos
Wildcards (curingas) são usados quando o tipo exato é desconhecido ou irrelevante. São representados pelo ponto de interrogação ?. Existem três tipos:
Blogs
Book Recommendations
Leia também