2015-12-30 2 views
1

Проблема в том, что у меня есть этот метод createNode(), который создает узел в дереве, а затем, если это уездный узел, он добавляет его в ArrayList<Tree> treeLeaves, и я делаю вызов этот метод во время просмотра treeLeaves ArrayList, как это:Java - добавление элементов в массив ArrayList при просмотре его

Iterator<Tree> iter = treeLeaves.iterator(); 
    while (iter.hasNext()) { 
     iter.next().createNode(); 
    } 

Или так:

For (Tree cursor : treeLeaves) { 
     cursor.createNode(); 
    } 

Но я держу имея это исключение:

Exception in thread "main" java.util.ConcurrentModificationException 

Даже если надеть коды ниже в блоке snychronized(treeLeaves){}. P.S: Я не знаю, полезно ли это или нет; это n-Tree.

+0

Я считаю, что есть еще одна ключевая информация, которую вы не показываете: на основании того, что вы показали нам, вы не меняете список ('treeLeaves') при его итерации. Вышеприведенный код не должен вызывать 'ConcurrentModificationException' (по крайней мере, не из' treeLeaves') –

+0

@AdrianShum Я сказал ниже, что метод '.createNode()' добавляет узел, а если это уездный узел, он добавляет его в 'treeLeaves '. Разве это еще не исчерпывающе? –

+0

oops, я понимаю, что вы там имеете в виду. Coz это не выглядит так нормально, поэтому я пропустил вашу точку там. –

ответ

2

для ArrayList, вы могли бы избежать итератор только с помощью индекса:

for (int i = 0; i < treeLeaves.size(); i++) { 
    Tree current = treeLeaves.get(i); 
    // your code 
} 

Пока единственное, что вы делаете, добавляется к концу массива, и вы не вставляете его в середине или в начале или не удаляете какие-либо элементы, это будет работать. treeLeaves.size() будет пересчитываться каждый раз, когда вы проходите цикл, а это означает, что если вы добавите его до конца, размер будет пересчитан, а i получит новые предметы. Да, использование старомодного цикла не так «круто», как итератор, но оно работает.

Я не рекомендую использовать это для любого вида List либо, кроме ArrayList, потому что в целом, get(i) придется начинать с начала списка и шаг через каждый элемент (если среда выполнения не оптимизирует случай, когда вы используя get(i+1) после get(i), что было бы не слишком сложно, но я не знаю, делают ли это реализации).Однако для ArrayListget(i) следует принимать постоянное время.

+0

Да, спасибо @ajb, на самом деле это уловка, как только вы узнаете путь итератора. Это не делает вас больше использовать цикл «старомодный». Во всяком случае, это помогает, поэтому еще раз спасибо. –

5

вам нужен ConcurrentList ...

http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.html

чтения Is there a concurrent List in Java's JDK?

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

+0

синхронизированный список не поможет. 'ConcurrentModificationException' означает больше, чем многопоточный доступ к коллекции. –

+0

Okey благодарю вас за то, что вы очень много @Ya Wang, я собираюсь попробовать, и я буду intouch –

+0

Действительно, это здорово, у меня больше нет Exception. Спасибо. –

1

Это связано с тем, что в Java, когда создается итератор, вы не можете изменить базовую структуру данных. Улучшенный для цикла "для (Дерево курсора: treeLeaves))" использует Итератор.

Как я сказал: «Также вы не можете изменить arraylist при просмотре его ... Вместо этого вы можете использовать буфер в памяти tempoaray для редактирования текущего списка, если хотите».

0

Вкратце, в большинстве случаев, если вы меняете структуру коллекции, все и без того открытые итераторы становятся недействительными. (Некоторое исключение в том числе с использованием Одновременные коллекций или модификация осуществляется с помощью итератора, или т.п.)

Ваша проблема может быть легко продемонстрирована:

List<Node> treeLeaves = new ArrayList<>(); 

//... add something to treeLeaves 

for (leaf : treeLeaves) { 
    treeLeaves.add(new Node()); 
} 

В вашем случае, это может быть легко решена создание новой коллекции итерировать:

List<Node> treeLeaves = new ArrayList<>(); 
//... add something to treeLeaves 

List<Node> tempLeaves = new ArrayList<>(treeLeaves);  
for (leaf : tempLeaves) { 
    treeLeaves.add(new Node()); 
} 
+0

Проблема заключается в том, что я должен дойти до расширения 'treeLeaves' ArrayList. Использование временного списка не работает, поскольку обновление не выполняется во время просмотра. –

Смежные вопросы