Ao resolver desafios em plataformas como LeetCode ou trabalhar no desenvolvimento cotidiano de sistemas, o domínio da biblioteca padrão do Java (JDK) pode aumentar significativamente a produtividade. Existem métodos integrados que simplificam a manipulação de coleções, arrays e strings, evitando a necessidade de implementar lógica redundente. Abaixo, detalhamos algumas dessas funcionalidades essenciais.
1. Manipulação de Arrays
A classe java.util.Arrays oferece métodos estáticos fundamentais para lidar com vetores de forma eficiente.
Ordenação: O método Arrays.sort() utiliza o algoritmo Dual-Pivot Quicksort para tipos primitivos, garantindo complexidade média de O(n log n).
int[] valores = {15, 3, 9, 1, 7};
Arrays.sort(valores);
// Resultado: [1, 3, 7, 9, 15]
System.out.println(Arrays.toString(valores));
Para ordenar de forma decrescente ou utilizar critérios personalizados, podemos usar lambdas com tipos objetos:
Integer[] dados = {5, 12, 8, 2, 10};
Arrays.sort(dados, (a, b) -> b - a);
// Resultado: [12, 10, 8, 5, 2]
Preenchimento: Para inicializar um array com um valor padrão sem recorrer a loops manuais:
int[] buffer = new int[5];
Arrays.fill(buffer, -1);
// Resultado: [-1, -1, -1, -1, -1]
2. Operações com Listas (ArrayList)
A flexibilidade das listas em Java é ampliada por métodos de conversão e utilitários da classe Collections.
Conversão entre Arrays e Listas:
// Array para Lista
String[] coresArray = {"Azul", "Verde", "Vermelho"};
List<String> listaCores = new ArrayList<>(Arrays.asList(coresArray));
// Lista para Array
String[] novoArray = listaCores.toArray(new String[0]);
Inversão de Elementos: Útil para problemas que envolvem pilhas ou reversão de resultados.
List<Integer> sequencia = new ArrayList<>(List.of(1, 2, 3, 4, 5));
Collections.reverse(sequencia);
// Resultado: [5, 4, 3, 2, 1]
Remoção de Duplicatas Estruturais: Em Java, listas que possuem os mesmos elementos na mesma ordem são consideradas iguais pelo método equals(). Isso permite usar um Set para filtrar listas duplicadas dentro de uma coleção de resultados.
Set<List<Integer>> setUnico = new HashSet<>();
setUnico.add(List.of(1, 2));
setUnico.add(List.of(1, 2));
// O Set conterá apenas um elemento [1, 2]
3. Mapas e Dicionários (HashMap)
O HashMap é crucial para reduzir a complexidade de busca de O(n) para O(1).
Cópia de Mapas: É possível clonar o conteúdo de um mapa diretamente via construtor ou pelo método putAll().
Map<String, Integer> original = Map.of("A", 1, "B", 2);
Map<String, Integer> copia = new HashMap<>(original);
4. Processamento de Strings
Strings são imutáveis em Java, e métodos utilitários facilitam sua formatação e divisão.
Divisão por Espaços (Regex): Para lidar com múltiplos espaços em branco entre palavras:
String texto = "Algoritmos são legais";
String[] palavras = texto.split("\\s+");
// Resultado: ["Algoritmos", "são", "legais"]
Junção de Elementos: O método String.join() é o inverso do split, conectando elementos com um delimitador.
List<String> componentes = List.of("java", "util", "Arrays");
String path = String.join(".", componentes);
// Resultado: "java.util.Arrays"
5. Otimização com Operadores Bitwise
Operações no nível de bit são processadas diretamente pela CPU, sendo extremamente rápidas para certas verificações matemáticas.
Verificação de Paridade: Em vez de usar o operador de módulo (%), o operador AND bitwise pode identificar números pares ou ímpares.
int n = 7;
boolean isImpar = (n & 1) == 1; // true
boolean isPar = (n & 1) == 0; // false
Deslocamento de Bits (Shift): Substitui multiplicações ou divisões por potências de 2.
int valor = 10;
int dobrado = valor << 1; // 10 * 2 = 20
int metade = valor >> 1; // 10 / 2 = 5