Exemplo de lista de usuários:

Usuários com pontuação e se são moderadores ou não:

Usuario user1 = new Usuario("Paulo Silveira", 150, true);
Usuario user2 = new Usuario("Rodrigo Turini", 120, true);
Usuario user3 = new Usuario("Guilherme Silveira", 90);
Usuario user4 = new Usuario("Sergio Lopes", 120);
Usuario user5 = new Usuario("Adriano Almeida", 100);
List usuarios = Arrays.asList(user1, user2, user3, user4, user5);

Mapeando pontuação para lista de usuários:

Abordagem tradicional:

Usando HashMap e verificando a existência de uma lista para cada pontuação.

Adicionando os usuários a listas de pontuação:

Map> pontuacao = new HashMap<>();
for(Usuario u: usuarios) {
if(!pontuacao.containsKey(u.getPontos())) {
pontuacao.put(u.getPontos(), new ArrayList<>());
}
pontuacao.get(u.getPontos()).add(u);
}

Exemplo de saída:

{
100=[Usuario Adriano Almeida],
150=[Usuario Paulo Silveira],
120=[Usuario Rodrigo Turini, Usuario Sergio Lopes],
90=[Usuario Guilherme Silveira]
}

Exemplo: ListaTradicional.java

Usando computeIfAbsent:

Usando Map.computeIfAbsent() para simplificar o código:

Map> pontuacao = new HashMap<>();
for(Usuario u: usuarios) {
pontuacao.computeIfAbsent(u.getPontos(), user -> new ArrayList<>()).add(u);
}

Exemplo: ListaComputeIfAbsent.java

Usando Streams e groupingBy:

A solução mais funcional com Collectors.groupingBy:

Map> pontuacao = usuarios.stream()
.collect(Collectors.groupingBy(Usuario::getPontos));

Particionando usuários em moderadores e não moderadores:

Usando partitioningBy para dividir usuários:

Map> moderadores = usuarios.stream()
.collect(Collectors.partitioningBy(Usuario::isModerador));

Exemplo de saída:

{
false=[Usuario Guilherme Silveira, Usuario Sergio Lopes, Usuario Adriano Almeida],
true=[Usuario Paulo Silveira, Usuario Rodrigo Turini]
}

Exemplo: ListaGroupPart.java

Usando mapping e toList para transformar os dados:

Gerando uma lista de nomes dos usuários por tipo:

Map> nomesPorTipo = usuarios.stream()
.collect(Collectors.partitioningBy(
Usuario::isModerador,
Collectors.mapping(Usuario::getNome, Collectors.toList())
));

Exemplo de saída:

{
false=[Guilherme Silveira, Sergio Lopes, Adriano Almeida],
true=[Paulo Silveira, Rodrigo Turini]
}

Somando pontos dos moderadores e não moderadores:

Usando summingInt para calcular a soma de pontos:

Map pontuacaoPorTipo = usuarios.stream()
.collect(Collectors.partitioningBy(
Usuario::isModerador,
Collectors.summingInt(Usuario::getPontos)
));

Exemplo de saída:

{false=310, true=270}

Concatenando nomes dos usuários:

Usando Collectors.joining() para concatenar nomes:

String nomes = usuarios.stream()
.map(Usuario::getNome)
.collect(Collectors.joining(", "));

Exemplo: NomePontoTipo.java

Vantagens do uso de coletores e streams:

Estilo funcional: Código mais enxuto e expressivo.

Menos efeitos colaterais: Favorece a imutabilidade das coleções originais.

Facilidade para paralelização: Menos mutabilidade facilita a execução paralela.