Generics em Java: para que servem e como usar para iniciantes
\n\nSe você está começando a estudar Java, mais cedo ou mais tarde encontrará o conceito de Generics (tipos genéricos). Esse poderoso recurso da linguagem permite escrever código mais flexível, seguro e reutilizável. Neste artigo, explicaremos de forma simples o que são Generics, para que servem e como aplicá-los na prática.
\n\nO que são Generics em Java?
\n\nGenerics (do inglês "generic" — geral, genérico) é um mecanismo do Java que permite criar classes, interfaces e métodos que trabalham com diferentes tipos de dados, garantindo uma verificação rigorosa de tipos em tempo de compilação.
\n\nSimplificando, os genéricos permitem dizer: "Esta classe ou método funcionará com qualquer tipo de dado, mas ainda não sei qual exatamente". O tipo é definido posteriormente, quando você cria um objeto ou chama um método.
\n\nO problema sem Generics
\n\nAntes do surgimento dos Generics (no Java 5), os desenvolvedores usavam casting de tipos e trabalhavam com Object. Isso era inconveniente e perigoso:
// Sem Generics (estilo antigo)\nList list = new ArrayList();\nlist.add("Olá");\nlist.add(123); // Erro? Não, o compilador permite\n\nString text = (String) list.get(0); // Casting obrigatório\n// String num = (String) list.get(1); // ClassCastException em tempo de execução!\n\nAqui, o compilador não vê o erro, mas o programa falha em tempo de execução. Os Generics resolvem esse problema.
\n\nPara que servem os Generics em Java?
\n\nOs Generics trazem três benefícios principais:
\n\n- \n
- Segurança de tipos (Type Safety) — os erros são detectados em tempo de compilação, não durante a execução do programa. \n
- Eliminação de casting explícito (No Casting) — não é necessário escrever
(String)toda vez. \n - Reutilização de código (Code Reuse) — uma classe ou método pode funcionar com diferentes tipos. \n
Exemplo com Generics
\n\nVeja como o código muda com o uso de genéricos:
\n\n// Com Generics\nList<String> list = new ArrayList<>();\nlist.add("Olá");\n// list.add(123); // Erro de compilação! Não é possível adicionar Integer\n\nString text = list.get(0); // Casting não é necessário\n// O compilador já sabe que é String\n\nO código ficou mais simples, seguro e legível.
\n\nComo usar Generics: construções principais
\n\nVamos analisar as três principais formas de aplicar genéricos: em classes, métodos e interfaces.
\n\n1. Classes genéricas
\n\nVocê pode criar uma classe que funciona com qualquer tipo. Para isso, após o nome da classe, entre colchetes angulares, indica-se o parâmetro de tipo (geralmente T, E, K, V):
// Classe genérica "Caixa"\npublic class Box<T> {\n private T content;\n\n public void put(T item) {\n this.content = item;\n }\n\n public T get() {\n return content;\n }\n}\n\n// Uso\nBox<String> stringBox = new Box<>();\nstringBox.put("Livro");\nString book = stringBox.get(); // Sem casting\n\nBox<Integer> intBox = new Box<>();\nintBox.put(42);\nint number = intBox.get();\n\n2. Métodos genéricos
\n\nÉ possível tornar genérico não a classe inteira, mas apenas um método específico. Isso é útil quando o método precisa processar diferentes tipos independentemente da classe:
\n\npublic class Utils {\n // Método genérico\n public static <T> void printArray(T[] array) {\n for (T element : array) {\n System.out.print(element + " ");\n }\n System.out.println();\n }\n}\n\n// Chamada\nInteger[] intArray = {1, 2, 3};\nString[] strArray = {"A", "B", "C"};\n\nUtils.printArray(intArray); // 1 2 3\nUtils.printArray(strArray); // A B C\n\n3. Interfaces genéricas
\n\nInterface