Java - Combine várias coleções

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 i1,
  Iterable i2) {
        return new Iterable() {
            public Iterator iterator() {
                return new Iterator() {
                    Iterator 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.