Quando precisamos acessar objetos por identificadores únicos em coleções, a conversão de listas para mapas oferece eficiência significativa. Considere a seguinte estrutura de entidade:
@Data
public class Funcionario {
private long codigo;
private String nome;
public Funcionario(long codigo, String nome) {
this.codigo = codigo;
this.nome = nome;
}
}
Para demonstrar a transformação, criamos uma lista de funcionários:
List<Funcionario> equipe = Arrays.asList(
new Funcionario(1001, "Ana"),
new Funcionario(1002, "Bruno"),
new Funcionario(1003, "Carla"),
new Funcionario(1004, "Daniel"),
new Funcionario(1005, "Eduarda")
);
Em abordagens tradicionais, buscar elementos específicos exigiria iteração manual:
Funcionario funcionario1002 = null;
Funcionario funcionario1004 = null;
for (Funcionario f : equipe) {
if (f.getCodigo() == 1002) funcionario1002 = f;
if (f.getCodigo() == 1004) funcionario1004 = f;
}
Uma solução intermediária envolve criar um mapa manualmente:
Map<Long, Funcionario> mapaFuncionarios = new HashMap<>();
for (Funcionario f : equipe) {
mapaFuncionarios.put(f.getCodigo(), f);
}
A API Stream do Java 8 simplifica esse processo através do método Collectors.toMap():
Map<Long, Funcionario> mapa =
equipe.stream().collect(Collectors.toMap(
Funcionario::getCodigo,
funcionario -> funcionario
));
Essa abordagem permite variações flexíveis conforme necessidades:
// Mapeamento para objeto completo
Map<Long, Funcionario> mapaCompleto =
equipe.stream().collect(Collectors.toMap(
Funcionario::getCodigo,
f -> f
));
// Extração de atributos específicos
Map<Long, String> nomesPorCodigo =
equipe.stream().collect(Collectors.toMap(
Funcionario::getCodigo,
Funcionario::getNome
));
// Transformação de valores
Map<Long, String> nomesFormatados =
equipe.stream().collect(Collectors.toMap(
Funcionario::getCodigo,
f -> f.getNome().toUpperCase() + "_FUNC"
));
Quando identificadores duplicados estão presentes, o coletor requer uma função de mesclagem:
List<Funcionario> equipeDuplicada = Arrays.asList(
new Funcionario(1001, "Ana"),
new Funcionario(1002, "Bruno"),
new Funcionario(1004, "Carla"),
new Funcionario(1004, "Daniel"), // Código repetido
new Funcionario(1005, "Eduarda")
);
// Prioriza primeiro valor encontrado
Map<Long, Funcionario> primeiroValor =
equipeDuplicada.stream().collect(Collectors.toMap(
Funcionario::getCodigo,
f -> f,
(anterior, atual) -> anterior
));
// Prioriza último valor encontrado
Map<Long, Funcionario> ultimoValor =
equipeDuplicada.stream().collect(Collectors.toMap(
Funcionario::getCodigo,
f -> f,
(anterior, atual) -> atual
));
// Concatena valores duplicados
Map<Long, String> valoresConcatenados =
equipeDuplicada.stream().collect(Collectors.toMap(
Funcionario::getCodigo,
Funcionario::getNome,
(anterior, atual) -> anterior + " | " + atual
));
Para lidar com valores nulos nos atributos, aplicamos tratamento prévio:
List<Funcionario> equipeComNulos = Arrays.asList(
new Funcionario(1001, "Ana"),
new Funcionario(1002, null) // Nome nulo
);
Map<Long, String> comTratamentoNulos =
equipeComNulos.stream().collect(Collectors.toMap(
Funcionario::getCodigo,
f -> Optional.ofNullable(f.getNome()).orElse("")
));