В java есть CopyOnWriteArrayList , который делает то, что вы хотите: он создает копию резервного массива каждый раз, когда вы что-либо меняете. Но это означает, что любая итерация «устанавливается в камень», как только вы начинаете итерацию, и поэтому вы можете по желанию удалять / добавлять в базовую коллекцию, не затрагивая при этом никаких работающих итераторов.
Вы также можете создать свой собственный тип коллекции с таким поведением. Это будет 3 лайнера:
public class ConstantIterationArrayList<T> extends ArrayList<T> {
public Iterator<T> iterator() {
return new ArrayList<T>(this).iterator();
}
}
(Приведенное выше делает копию списка, а затем дает вам итератор для копии, таким образом, удобно гарантируя, что любая модификация этого списка не окажет абсолютно никакого влияния на этот итератор).
Вот реальная проблема с вашим вопросом:
Выше время от времени будут создаваться копии основного хранилища данных (мой фрагмент выше делает это каждый раз, когда вы создаете итератор. CopyOnWriteArrayList
делает это каждый раз, когда вы вызываете remove()
или add()
). Операция «копирование основного хранилища данных» занимает O (n) время, т. Е. Для списка, который вдвое больше, требуется вдвое больше.
ArrayList
в общем обладает тем свойством, что операция remove()
, если только вы не удаляете элемент в конце или очень близко к концу списка, является операцией O (n) : удаление Элемент из списка занимает в два раза больше времени, если список в два раза больше.
К счастью, современные процессоры имеют значительные кэши и могут работать очень быстро на странице кэша. Что означает: несмотря на тот факт, что копирование данных выглядит неэффективно, на практике, если массив резервных копий помещается на странице или около того, он на намного быстрее, чем хранилища данных на основе семантики LinkedList
. Мы говорим о ~ 1000 элементов, которые можно брать или брать. (Обратите внимание, что почти все, что вы делаете с LinkedList
, это O (n) , и где ArrayList
хорошо работает с современной архитектурой процессора, LinkedList
имеет тенденцию работать очень плохо. Дело в том, что LinkedList
тоже очень редко правильный ответ!)
Итак, если у вас не более ~ 1000 элементов в этом списке, я бы выбрал CopyOnWriteArrayList
или пользовательский класс, который я написал для вас выше.
Однако, если у вас на больше этого значения, ArrayList
не является подходящим хранилищем данных для использования здесь. Даже если вы забудете о своих постоянных итерационных потребностях на данный момент; вызывать remove()
в списках больших массивов - плохая идея (если только удаление не очень близко к концу списка). В этом случае я бы в общих чертах наметил, какие именно операции вам нужно выполнить с этим типом данных, и какие действительно нужно выполнить быстро, и, как только у вас будет полный список, я постараюсь найти тип коллекции, который точно соответствует вашим потребностям, и в (вероятном) случае не существует ничего конкретного, что идеально подходит, сделайте это сами. Как и выше, когда вам нужно свернуть свой собственный тип данных, обычно хорошей идеей будет позволить большую часть работы выполнить существующими типами данных, поэтому либо расширьте существующий, либо инкапсулируйте один.