Java - объединение нескольких коллекций

Java - объединение нескольких коллекций

1. обзор

В этом руководстве мы проиллюстрируем, как объединить несколько коллекций в одну логическую коллекцию.

Мы рассмотрим пять различных подходов: два с использованием Java 8, один с использованием Guava, один с использованием коллекций Apache Commons и один с использованием только стандартного Java 7 SDK.

В следующих примерах рассмотрим следующие коллекции:

Collection collectionA = asList("S", "T");
Collection collectionB = asList("U", "V");

2. Использование API Java 8Stream

ИнтерфейсStream в Java API предоставляет полезные методы, упрощающие обработку коллекций. Давайте посмотрим на два его метода -concat() иflatMap() - которые используются для объединения коллекций.

Как только вы получитеStream, вы можете выполнять с ним агрегированные операции.

2.1. Использование методаconcat() __

Статический методconcat() логически объединяет дваStreams, создавая лениво сцепленныйStream, элементы которого являются элементами первогоStream, за которым следуют все элементы второгоStreamс.

В приведенном ниже примере давайте объединимcollectionA иcollectionB, используя методconcat():

Stream combinedStream = Stream.concat(
  collectionA.stream(),
  collectionB.stream());

Если вам нужно объединить более двухStreams, вы можете снова вызвать методconcat() из исходного вызова:

Stream combinedStream = Stream.concat(
  Stream.concat(collectionA.stream(), collectionB.stream()),
  collectionC.stream());

Важно отметить, что Java 8Streamsнельзя использовать повторно, поэтому вы должны учитывать это при назначении их переменным.

2.2. Использование методаflatMap() __

МетодflatMap() возвращаетStream после замены каждого элемента этогоStream содержимым сопоставленногоStream, которое создается путем применения предоставленной функции сопоставления к каждому элементу.

Пример ниже демонстрирует слияние коллекций с использованием методаflatMap(). Первоначально вы получаетеStream, элементами которого являются две коллекции, а затем вы сглаживаетеStream перед тем, как собрать его в объединенный список:

Stream combinedStream = Stream.of(collectionA, collectionB)
  .flatMap(Collection::stream);
Collection collectionCombined =
  combinedStream.collect(Collectors.toList());

3. Использование гуавы

Библиотека Guava от Google предоставляет несколько удобных методов для работы с коллекциями и может использоваться с Java 6 или новее.

3.1. Использование методаIterables.concat()

МетодIterables.concat() - один из удобных методов Guava, который используется для объединения коллекций:

Iterable combinedIterables = Iterables.unmodifiableIterable(
  Iterables.concat(collectionA, collectionA));

ВозвращаемыйIterable может быть преобразован в коллекцию:

Collection collectionCombined = Lists.newArrayList(combinedIterables);

3.2. Maven Dependency

Добавьте следующую зависимость в свой файл Mavenpom.xml, чтобы включить библиотеку Guava в свой проект:


    com.google.guava
    guava
    20.0

Вы можете найти последнюю версию библиотеки Guava в репозиторииMaven Central.

4. Использование коллекций Apache Commons

Apache Commons Collections - это еще одна библиотека утилит, которая помогает в работе с различными коллекциями. Библиотека предоставляет два служебных метода, которые можно использовать для объединения коллекций. В этом разделе давайте разберемся, как работают эти методы.

4.1. Использование методаIterableUtils.chainedIterable()

КлассIterableUtils предоставляет служебные методы и декораторы для экземпляровIterable. Он предоставляет методchainedIterable(), который можно использовать для объединения несколькихIterable в один.

Iterable combinedIterables = IterableUtils.chainedIterable(
  collectionA, collectionB);

4.2. Использование методаCollectionUtils.union()

Служебные методы и декораторы для экземпляровCollection предоставляются классомCollectionUtils. Методunion() из этого класса возвращаетCollection, содержащий объединение заданных экземпляровIterable.

Iterable combinedIterables = CollectionUtils.union(
  collectionA, collectionB);

В случае методаunion() мощность каждого элемента в возвращаемой коллекции будет равна максимальной мощности этого элемента в двух заданныхIterables. Это означает, что объединенная коллекция состоит только из элементов первой коллекции и элементов второй коллекции, которых не было в первой.

4.3. Maven Dependency

Добавьте следующую зависимость в свой файл Mavenpom.xml, чтобы включить библиотеку коллекций Apache Commons в свой проект:


    org.apache.commons
    commons-collections4
    4.1

Вы можете найти последнюю версию библиотеки Apache Commons в репозиторииMaven Central.

5. Использование Java 7

Если вы все еще используете Java 7 и хотите избегать сторонних библиотек, таких как Guava, вы можете использовать методaddAll() для объединения элементов из нескольких коллекций, или вы можете написать свои собственные служебные методы для объединенияIterables .

5.1. Использование методаaddAll()

Конечно, самым простым решением для объединения коллекций является использование методаaddAll(), как в следующем примереList, однако стоит отметить, что этот метод создает новую коллекцию с дополнительными ссылками на те же объекты, которые в первых двух сборниках:

List listC = new ArrayList<>();
listC.addAll(listA);
listC.addAll(listB);

5.2. Написание собственного методаconcat()

В приведенном ниже примере определяется методconcat(), который принимает дваIterables и возвращает объединенный объектIterable:

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();
                    }
                };
            }
        };
    }

Методconcat() можно вызвать, передав две коллекции в качестве аргументов:

Iterable combinedIterables = concat(collectionA, collectionB);
Collection collectionCombined = makeListFromIterable(combinedIterables);

Если вам нужно, чтобыIterable был доступен какList, вы также можете использовать методmakeListFromIterable(), который создаетList с использованием членовIterable:

public static  List makeListFromIterable(Iterable iter) {
    List list = new ArrayList();
    for (E item : iter) {
        list.add(item);
    }
    return list;
}

6. Заключение

В статье обсуждалось несколько различных способов логически объединить две коллекции в Java без создания дополнительных ссылок на объекты, которые они содержат.

Код для этого руководства доступенover on Github.