Утилита для объединения нескольких коллекций в одну коллекцию одного и того же типа экземпляра - PullRequest
0 голосов
/ 09 июля 2020

Хотите написать эффективный и удобный для клиента способ слияния нескольких неизменяемых коллекций в одну коллекцию того же типа экземпляра

Что-то вроде

public static <K> Collection<K> merge(Collection<K>... collection) {
   // return merged collection
}

Для этого вместе с набором коллекций клиентам также потребуется передать либо тип экземпляра объединенной коллекции (в этом случае мне нужно будет проверить совместимость с набором коллекций). Я не хочу go этот маршрут

Можно ли каким-либо образом вывести тип коллекции и проверить, что все коллекции принадлежат к одному типу, и создать новый экземпляр того же типа? Или это недопустимый вариант использования для реализации слияния общего назначения, и лучше просто предоставить отдельные реализации слияния для каждого типа?

1 Ответ

2 голосов
/ 09 июля 2020

Это непросто и требует заранее знать точный список поддерживаемых вами типов. Это еще больше усложняется тем фактом, что неизменяемые типы, возвращаемые, например, java.util.List.of(a, b), не являются типами publi c, а их полное имя типа не является частью spe c (что означает: оно может измениться в следующий выпуск java, и это не будет считаться нарушением обратной совместимости; поэтому, если вы полагаетесь на имя, ваш код будет иметь высокую нагрузку на обслуживание).

Возможно, лучше разрешить любой тип коллекций и даже разнородный список коллекций (добавьте в него набор, Guava ImmutableList, List.of () и Collections.singleton - вашему коду все равно, и он объединит их все) и имеет различные методы, каждый из которых возвращает желаемый тип коллекции.

Например:

import com.google.common.collect.ImmutableList;
public static <K> ImmutableList<K> mergeToList(Collection<K>... collections) {
    var out = ImmutableList.<K>builder();
    for (Collection<K> c : collections) out.addAll(c);
    return out.build();
}

Альтернативой может быть что-то довольно уродливое, например:

import com.google.common.collect.ImmutableList;
public static <K, C extends Collection<K>> C merge(C... collections) {
    if (collections.length == 0) throw new IllegalArgumentException("So many problems; one of them is that it becomes impossible to merge zero collections");
    Class<?> type = collections[0].getClass();
    for (C c : collections) if (c.getClass() != type) throw new IllegalArgumentException("Only pass one kind of collection");
    if (type == ImmutableList.class) {
        // specific code to merge immutable lists.
    } else if (type == Collections.singleton("dummy").getClass()) {
        // specific code to merge j.u.Collections singletons.
    } else if (type == List.of().getClass()) {
        // this becomes virtually impossible; List.of()'s returned type depends on the number of args...
    } else {
        throw new IllegalArgumentException("Unsupported type: " + type);
    }
}

Надеюсь, это проясняет, почему вы действительно не можете этого сделать. Последний вариант - иметь метод слияния, который принимает в качестве параметра тип для слияния, но нет способа узнать, как СДЕЛАТЬ тип коллекции. Учитывая com.google.common.collect.ImmutableList, без жесткого кодирования в исходный код, как это сделать, как бы вы узнали, как построить новый?

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...