Coletar um fluxo Java em uma coleção imutável
1. Introdução
Neste artigo rápido, vamos dar uma olhada em várias maneiras de coletar JavaStreams emCollections – imutáveis, que requerem uma abordagem especial porqueCollectors padrão funciona apenas com estruturas de dados mutáveis.
2. Dependência do Maven
Vamos usar a biblioteca Guava do Google para gerar alguns de nossos exemplos:
com.google.guava
guava
22.0
Podemos obter a versão mais recente dessa dependência emhere.
3. UsandocollectingAndThen() de Java
O métodocollectingAndThen() da classeCollectors de Java aceita umCollector e umfinisherFunction que é aplicado ao resultado retornado deCollector:
@Test
public void whenUsingCollectingToImmutableList_thenSuccess() {
List givenList = Arrays.asList("a", "b", "c");
List result = givenList.stream()
.collect(collectingAndThen(toList(), ImmutableList::copyOf));
System.out.println(result.getClass());
}
Já que não podemos usar toCollection() Collector diretamente,, precisamos coletar elementos para uma lista temporária e, em seguida, construir uma lista imutável a partir dela.
Neste exemplo, estamos convertendo aStream emList usando o coletortoList() e criando umImmutableList. OImmutableList faz parte da biblioteca Guava. Se registrarmos a saída no console, obteremos a classe do
Se registrarmos a saída no console, obteremos a classe da implementaçãoList subjacente:
class com.google.common.collect.RegularImmutableList
4. UsandoCollectors de Guava
Começando com Guava 21, com cada classe imutável vem um acompanhanteCollector que é tão fácil de usar quantoCollectors: padrão
@Test
public void whenCollectToImmutableList_thenSuccess() {
List list = IntStream.range(0, 9)
.boxed()
.collect(ImmutableList.toImmutableList());
}
A instância resultante é oRegularImmutableList:
class com.google.common.collect.RegularImmutableList
5. Construindo um coletor personalizado
Agora, vamos dar um passo adiante e implementar nossoCollector personalizado. Para atingir esse objetivo, vamos usar o métodoCollector.of() estático:
public static Collector, List> toImmutableList() {
return Collector.of(ArrayList::new, List::add,
(left, right) -> {
left.addAll(right);
return left;
}, Collections::unmodifiableList);
}
Para saber mais sobre como implementarCollectors personalizado, dê uma olhada na Seção 4 dethis article. E é isso. O método acima faz parte da nossa classe personalizada
Podemos usá-lo agora como qualquer outroCollectors integrado:
@Test
public void whenCollectToMyImmutableListCollector_thenSuccess() {
List givenList = Arrays.asList("a", "b", "c", "d");
List result = givenList.stream()
.collect(MyImmutableListCollector.toImmutableList());
}
Finalmente, vamos verificar o resultado:
class java.util.Collections$UnmodifiableRandomAccessList
5.1. Tornando oMyImmutableListCollector genérico
Nossa implementação tem uma limitação - ela sempre retorna uma instância imutável apoiada por umArrayList. No entanto, com pequenas melhorias, podemos fazer com que esse coletor retorne um tipo especificado pelo usuário:
public static > Collector> toImmutableList(
Supplier supplier) {
return Collector.of(
supplier,
List::add, (left, right) -> {
left.addAll(right);
return left;
}, Collections::unmodifiableList);
}
Agora, em vez de determinar osupplier na implementação do método, estamos solicitando osupplier do usuário:
@Test
public void whenPassingSupplier_thenSuccess() {
List givenList = Arrays.asList("a", "b", "c", "d");
List result = givenList.stream()
.collect(MyImmutableListCollector.toImmutableList(LinkedList::new));
}
Observe que agora estamos usandoLinkedList em vez deArrayList. Vamos fazer isso e ver os resultados:
class java.util.Collections$UnmodifiableList
Desta vez, obtivemosUnmodifiableList em vez deUnmodifiableRandomAccessList.
6. Conclusão
Neste breve artigo, vimos várias maneiras de coletar umStream em umCollection imutável.
Certifique-se de verificar o código-fonte completo deste artigoover on GitHub.