Создание общей копии Set<String> в конструкторе
Я не нашел прямого ответа на этот конкретный вопрос, так что... Предположим, класс:
class MyClass {
private final Set<String> tags;
MyClass(Set<String> initialTags) {
this.tags = ???(initialtags);
}
}
Я просто хочу копию, не заботясь о точной реализации набора, с минимальными издержками, так что в основном это прямая копия любого внутреннего состояния, которое имеет initialTags. Я не могу использовать clone
, поскольку Set является интерфейсом. Это возможно, или я должен использовать что-то вроде new HashSet<String>(tags);
Нужно принять решение о типе?
Допущения: Заданный тип элемента ограничен неизменным. Я могу доверять звонящему, чтобы не пропустить сломанный initialTags
Установите реализацию, и я могу доверять ей, чтобы иметь достаточно хорошую производительность для любого внутреннего использования в этом классе.
Я думаю о попытке отражения и клонирования (), но это кажется немного грязным...
3 ответа
Гуава предоставляет метод для этого:
/**
* Returns an immutable set containing the given elements, in order. Repeated
* occurrences of an element (according to {@link Object#equals}) after the
* first are ignored. This method iterates over {@code elements} at most once.
*
* <p>Note that if {@code s} is a {@code Set<String>}, then {@code
* ImmutableSet.copyOf(s)} returns an {@code ImmutableSet<String>} containing
* each of the strings in {@code s}, while {@code ImmutableSet.of(s)} returns
* a {@code ImmutableSet<Set<String>>} containing one element (the given set
* itself).
*
* <p>Despite the method name, this method attempts to avoid actually copying
* the data when it is safe to do so. The exact circumstances under which a
* copy will or will not be performed are undocumented and subject to change.
*
* @throws NullPointerException if any of {@code elements} is null
*/
public static <E> ImmutableSet<E> copyOf(Iterable<? extends E> elements) {
return (elements instanceof Collection)
? copyOf(Collections2.cast(elements))
: copyOf(elements.iterator());
}
В зависимости от ожидаемого размера начальных тегов, вы можете предпочесть разные реализации; код ниже показывает более быстрое время для копий на основе конструктора, когда i is < 100000
, но клон быстрее, когда i > 1000000
, Если вы действительно хотите использовать clone
вы всегда можете использовать isinstance
определить, какие из (6) хорошо известных конкретных реализаций (которые реализуют cloneable
) это, кроме того, у вас нет никаких гарантий initialTags
есть это.
static Set<String> byCloning(HashSet<String> initialTags) {
return (Set<String>) initialTags.clone();
}
static Set<String> byConstructor(Set<String> initialTags) {
return new HashSet<String>(initialTags);
}
public static void main(String[] args) {
int N = Integer.parseInt(args[0]);
HashSet<String> mySet = new HashSet<String>();
for (int n = 0 ; n < N ; n++) mySet.add(Integer.toString(n));
long start = System.currentTimeMillis();
byCloning(mySet);
long end = System.currentTimeMillis();
System.out.println(" time take in milli seconds for cloning = " + (end-start) );
start = System.currentTimeMillis();
byConstructor(mySet);
end = System.currentTimeMillis();
System.out.println(" time take in milli seconds by constructor = " + (end-start) );
}
Либо примите решение о типе в зависимости от типа доступа, который вам необходим для набора, либо вы можете попробовать использовать Collections.unmodifiableSet():
class MyClass {
private final Set<String> tags;
MyClass(Set<String> initialTags) {
this.tags = Collections.unmodifiableSet(initialTags);
}
}