Java: итерация по набору, в то время как содержимое набора изменяется


Я хочу выполнить итерацию над набором, но содержимое набора будет изменяться во время его итерации. Я хочу перебирать исходный набор в момент создания итератора и не перебирать ни один из новых элементов, добавленных в набор. Как такое возможно? Является ли это поведение set по умолчанию или как я могу это сделать?

Один из способов, который я могу придумать, - это получить новый набор из исходного набора, который не будет изменен, но это кажется неэлегантным, и должно быть лучшее решение.
6   7   2012-06-19 22:18:20

6 ответов:

Создание моментального снимка набора кажется мне абсолютно правильным решением, если вы хотите убедиться, что не видите никаких новых элементов. Есть некоторые наборы, такие как ConcurrentSkipListSet что позволит вам продолжать итерацию, но я не могу видеть какие-либо гарантии вокруг поведения итератора с точки зрения видения новых элементов.

Править: CopyOnWriteArraySet имеет требования, которые вам нужны, но пишет дорого, что звучит так, как будто это не подходит для вас.

Это единственные наборы, которые я могу видеть в java.util.concurrent, что является естественной упаковкой для таких коллекций. Сделать копию все равно, скорее всего, будет проще :)

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

Прямого пути к этому нет. Тем не менее, один из вариантов, который довольно хорош, состоит в том, чтобы иметь два набора-основной набор, который вы повторяете, и вторичный набор в которую вы вставляете все новые элементы, которые необходимо добавить. Затем можно выполнить итерацию по первичному набору, а затем, когда это будет закончено, перейти и использовать addAll, чтобы добавить все новые элементы в первичный набор.

Например:

Set<T> masterSet = /* ... */

Set<T> newElems = /* ... */
for (T obj: masterSet) {
     /* ... do something to each object ... */
}

masterSet.addAll(newElems);

Надеюсь, это поможет!

Изготовление копии Set есть элегантное решение.

Set<Obj> copyOfObjs = new HashSet<Obj>(originalSet);
for(Obj original : originalSet) {
    //add some more stuff to copyOfObjs
}

Вы можете использоватьConcurrentHashMap с фиктивными ключами. Или ConcurrentSkipListSet

Как здесь предположили другие, нет оптимального решения для того, что вы ищете. Все зависит от варианта использования вашего приложения или использования набора
Поскольку Set-это интерфейс, вы можете определить свой собственный класс DoubleSet, который будет реализовывать Set и, скажем, будет использовать два поля HashSet.
При извлечении итератора следует отметить, что один из этих наборов находится в режиме "только взаимодействие", поэтому метод add будет добавлять только к другому набору


Я все еще новичок в этом деле. Stackoverlflow, поэтому мне нужно понять, как встраивать код в мои ответы : (но в целом у вас должен быть класс под названием MySet (Generic of generic type T), реализующий набор generic type T.
Вам нужно реализовать все методы и иметь два поля - одно называется iterationSet, а другое-insertionSet.
У вас также будет логическое поле, указывающее, нужно ли вставлять в два набора или нет. При вызове метода iterator() это логическое значение должно быть равно false, то есть вы следует вставить только в insertionSet.
У вас должен быть метод, который синхронизирует содержимое двух наборов, как только вы закончите с итератором.
Надеюсь, я выразился ясно

Теперь, когда ОП уточнил требования, решения являются

  1. скопируйте набор перед итерацией
  2. Use CopyOnWriteArraySet
  3. Напишите свой собственный код и постарайтесь быть умнее многих умных людей.

Недостатком #1 является то, что вы всегда копируете набор, даже если он может быть не нужен (например, если никакие вставки на самом деле не происходят во время итерации), я бы предложил вариант #2, Если вы не докажете, что частые вставки вызывают реальную проблема производительности.