Java - Combine várias coleções
1. Visão geral
Neste tutorial, ilustraremos como concatenar várias coleções em uma coleção lógica.
Vamos explorar cinco abordagens diferentes - duas usando Java 8, uma usando Guava, uma usando Apache Commons Collections e uma usando apenas o Java 7 SDK padrão.
Nos exemplos a seguir, vamos considerar as seguintes coleções:
Collection collectionA = asList("S", "T");
Collection collectionB = asList("U", "V");
2. Usando a API Java 8Stream
A interfaceStream na API Java fornece métodos úteis que facilitam o processamento de coleções. Vamos dar uma olhada em dois de seus métodos -concat()eflatMap() - que são usados para combinar coleções.
Depois de obter umStream, você pode executar operações agregadas nele.
2.1. Usando o métodoconcat() __
O método estáticoconcat() combina doisStreams logicamente criando umStream concatenado preguiçosamente cujos elementos são todos os elementos do primeiroStream seguidos por todos os elementos do segundoStream.
No exemplo abaixo, vamos combinarcollectionAecollectionB usando o métodoconcat():
Stream combinedStream = Stream.concat(
collectionA.stream(),
collectionB.stream());
Se você precisar combinar mais de doisStreams, poderá invocar o métodoconcat() novamente de dentro da invocação original:
Stream combinedStream = Stream.concat(
Stream.concat(collectionA.stream(), collectionB.stream()),
collectionC.stream());
É importante observar que Java 8Streams não são reutilizáveis, portanto, você deve levar isso em consideração ao atribuí-los às variáveis.
2.2. Usando o métodoflatMap() __
O métodoflatMap() retorna umStream após substituir cada elemento desteStream com o conteúdo de umStream mapeado que é produzido aplicando a função de mapeamento fornecida a cada elemento.
O exemplo abaixo demonstra a fusão de coleções usando o métodoflatMap(). Inicialmente, você obtém umStream cujos elementos são as duas coleções e, em seguida, achatarStream antes de coletá-lo em uma lista mesclada:
Stream combinedStream = Stream.of(collectionA, collectionB)
.flatMap(Collection::stream);
Collection collectionCombined =
combinedStream.collect(Collectors.toList());
3. Usando goiaba
A biblioteca Guava do Google fornece vários métodos de conveniência para operar em coleções e pode ser usada com Java 6 ou posterior.
3.1. Usando o métodoIterables.concat()
O métodoIterables.concat() é um dos métodos convenientes do Guava usado para mesclar coleções:
Iterable combinedIterables = Iterables.unmodifiableIterable(
Iterables.concat(collectionA, collectionA));
OIterable que é retornado pode ser convertido em uma coleção:
Collection collectionCombined = Lists.newArrayList(combinedIterables);
3.2. Dependência do Maven
Adicione a seguinte dependência ao arquivo Mavenpom.xml para incluir a biblioteca Guava em seu projeto:
com.google.guava
guava
20.0
Você pode encontrar a versão mais recente da biblioteca Guava no repositórioMaven Central.
4. Usando coleções do Apache Commons
O Apache Commons Collections é mais uma biblioteca de utilitários que ajudam no trabalho com as várias coleções. A biblioteca fornece dois métodos utilitários que podem ser usados para combinar coleções. Nesta seção, vamos entender como esses métodos funcionam.
4.1. Usando o métodoIterableUtils.chainedIterable()
A classeIterableUtils fornece métodos utilitários e decoradores para instâncias deIterable. Ele fornece o métodochainedIterable(), que pode ser usado para combinar váriosIterables em um único.
Iterable combinedIterables = IterableUtils.chainedIterable(
collectionA, collectionB);
4.2. Usando o métodoCollectionUtils.union()
Métodos utilitários e decoradores para instâncias deCollection são fornecidos pela classeCollectionUtils. O métodounion() desta classe retorna umCollection contendo a união das instânciasIterable fornecidas.
Iterable combinedIterables = CollectionUtils.union(
collectionA, collectionB);
No caso do métodounion(), a cardinalidade de cada elemento na coleção retornada será igual ao máximo da cardinalidade desse elemento nos doisIterables dados. Isso significa que a coleção combinada consiste apenas nos elementos da primeira coleção e nos elementos da segunda coleção que não estavam presentes na primeira.
4.3. Dependência do Maven
Adicione a seguinte dependência ao arquivo Mavenpom.xml para incluir a biblioteca Apache Commons Collections em seu projeto:
org.apache.commons
commons-collections4
4.1
Você pode encontrar a versão mais recente da biblioteca Apache Commons no repositórioMaven Central.
5. Usando Java 7
Se você ainda está usando Java 7 e deseja evitar bibliotecas de terceiros, como Guava, você pode usar o métodoaddAll() para combinar elementos de várias coleções ou pode escrever seus próprios métodos de utilitário para combinarIterables .
5.1. Usando o métodoaddAll()
Claro que a solução mais simples para combinar coleções é usar o métodoaddAll(), como no seguinte exemploList, no entanto, é importante notar que este método cria uma nova coleção com referências adicionais para os mesmos objetos que são nas duas primeiras coleções:
List listC = new ArrayList<>();
listC.addAll(listA);
listC.addAll(listB);
5.2. Escrevendo um métodoconcat() personalizado
O exemplo a seguir define um métodoconcat() que aceita doisIterablese retorna um objetoIterable mesclado:
public static Iterable concat(
Iterable extends E> i1,
Iterable extends E> i2) {
return new Iterable() {
public Iterator iterator() {
return new Iterator() {
Iterator extends E> listIterator = i1.iterator();
Boolean checkedHasNext;
E nextValue;
private boolean startTheSecond;
void theNext() {
if (listIterator.hasNext()) {
checkedHasNext = true;
nextValue = listIterator.next();
} else if (startTheSecond)
checkedHasNext = false;
else {
startTheSecond = true;
listIterator = i2.iterator();
theNext();
}
}
public boolean hasNext() {
if (checkedHasNext == null)
theNext();
return checkedHasNext;
}
public E next() {
if (!hasNext())
throw new NoSuchElementException();
checkedHasNext = null;
return nextValue;
}
public void remove() {
listIterator.remove();
}
};
}
};
}
O métodoconcat() pode ser invocado passando as duas coleções como seus argumentos:
Iterable combinedIterables = concat(collectionA, collectionB);
Collection collectionCombined = makeListFromIterable(combinedIterables);
Se você precisa queIterable esteja disponível comoList, você também pode usar o métodomakeListFromIterable() que cria umList usando os membros deIterable:
public static List makeListFromIterable(Iterable iter) {
List list = new ArrayList();
for (E item : iter) {
list.add(item);
}
return list;
}
6. Conclusão
O artigo discutiu várias maneiras diferentes de combinar duas coleções logicamente em Java sem criar referências adicionais aos objetos que elas contêm.
O código para este tutorial está disponívelover on Github.