2013-11-27 72 views
0

我有一個在arraylist中的對象,名爲PowerUp。我希望這些是可點擊的,當它們被點擊時,它們將從屏幕上移除,並最終從數組列表中取出。我已將處理程序插入類HealthPack,該類繼而擴展PowerUp。我試圖訪問被點擊的某個HealthPack,並將其從列表中刪除。我一直得到它無法正常工作,或ConcurrentModificationException。這裏是我的代碼,我想一起工作:從數組列表中獲取點擊的對象

for (int i = 0; i < ((SurvivalMode) m).getPowerUps().size(); i++) { 
    PowerUp p = ((SurvivalMode) m).getPowerUps().get(i); 
    if (p.equals(hp)) { // HealthPack hp = this; 
     ((SurvivalMode) m).getPowerUps().remove(p); 
     addPoints(); 
    } 
} 

該電流代碼實際上拋出一個ConcurrentModificationException當我去上HealthPack時單擊列表既增加了,而另一個就是通過它進行迭代。我試着同步列表中的方法,但它沒有幫助。

如果一個方法試圖從列表中移除一個元素,而另一個方法是迭代整個列表或者是從列表中添加或移除一個元素,我該如何保持我的程序不會拋出ConcurrentModificationException

編輯:
這裏是實際變更針對項目的ArrayList一些額外的代碼:

if (powerups.size() >= 15 || isPaused()) return; 

    int gen = random.nextInt(10); 
    if (gen == 0) { 
     powerups.add(new HealthPack(this)); 
     addMouseListener(powerups.get(powerups.size() - 1).getMouseListener()); 
    } 
} 

和一些代碼,通過該名單實際上迭代(這將引發ConcurrentModificationException):

for (PowerUp p : powerups) p.update(); 

當前方法: 這裏是curre nt方法,我試圖從列表中刪除點擊,但它仍然不能很好地工作,因爲它不會刪除任何東西,或者它會刪除錯誤的東西,有時甚至會爲所有的方法調用方法其他PowerUp S IN列表:

Iterator<PowerUp> iter = ((SurvivalMode) m).getPowerUps().iterator(); 
while (iter.hasNext()) { 
    PowerUp p = (HealthPack) iter.next(); 
    if (p.equals(hp)) { 
     ((SurvivalMode) m).getPowerUps().remove(p); 
    } 
    CellDefender.getSounds().play(SoundType.HEALTH_PACK); 
    break; 
} 

更新2:
我最近做實際上是數組列表中的另一點內的複製,並部分地有助於減少我的更新中的錯誤(方法):

CopyOnWriteArrayList<PowerUp> cpowerups = new CopyOnWriteArrayList<PowerUp>(); 

for (int i = 0; i < powerups.size(); i++) { 
    cpowerups.add(powerups.get(i)); 
} 

for (PowerUp p : cpowerups) p.update(); 

而且我會喜歡e問一件事,是否有辦法檢測列表是否正在被修改,以及列表是否被修改爲跳出循環?

回答

0

您必須使用Iterator for loop從ArrayList中刪除元素。

Iterator<PowerUp> iter = ((SurvivalMode) m).getPowerUps().iterator(); 
while(iter.hasNext()) { 
    PowerUp p = iter.next(); 
    // your conditions to remove element here 
    iter.remove(); 
} 
+0

我將如何能夠從該迭代器獲取索引?這是我正在嘗試的代碼: \t'Iterator iter =((SurvivalMode)m).getPowerUps()。iterator(); PowerUp p =((SurvivalMode)m).getPowerUps()。get(???); (iter.equals((p)))iter.remove();如果(iter.equals((p)))iter.remove(); \t}' – CoderMusgrove

+0

你不需要索引。 'if(p.equals(hp))iter.remove();' – Alex

+0

當我這樣做的時候,它實際上並沒有在'if'語句中對代碼做任何事情;我試着拿出那個,如果它在'iter.remove();'' – CoderMusgrove

0

因爲我不知道你的整個代碼,我必須做出一些假設。 我的第一個假設是,你的有問題的代碼片段被PowerUp類的update方法以某種方式調用。

[1]所述,每個循環使用一個Iterator對象遍歷ArrayList的元素。

那些IteratorArrayList返回的對象是快速故障。 也就是說,如果ArrayList在創建這樣的Iterator對象之後以任何方式被修改,除了通過對象本身,它們的方法會拋出ConcurrentModificationException。 (參見[2]

如果我的假設是正確的,你的代碼for (PowerUp p : powerups) p.update();創建這樣一個Iterator對象,並修改其它給定的代碼片段中ArrayList。 這就是您爲什麼遇到與Alex提出的代碼相同的異常的原因。

你的問題的解決方案是使用一個CopyOnWriteArrayList的,每當我們通過遍歷CollectionArrayListLinkedList等),它創建的收集和迭代複製的元素的淺拷貝,這樣就可以修改原始集合而不發生ConcurrentModificationException。 也就是說,你有for (PowerUp p : CopyOnWriteArrayList(powerups) p.update();更換for (PowerUp p : powerups) p.update();和使用

Iterator<PowerUp> iter = ((SurvivalMode) m).getPowerUps().iterator(); 
while(iter.hasNext()) { 
    PowerUp p = iter.next(); 
    // your conditions to remove element here 
    iter.remove(); 
} 

所建議的亞歷克斯。

+0

'iter.remove()'在'CopyOnWriteArrayList'類中不可用,它會引發'UnsupportedOperationException'。 – CoderMusgrove

+0

啊,對不起。我看到了什麼問題。我制定了它不清楚。所以,在這裏我的更正:迭代你的元素,你必須使用'CopyOnWriteArrayList ** **除了**,當你想修改你的集合(在你的情況下,刪除一個元素)。這裏你必須使用@Alex建議的原始集合。 – ojlr

+0

我已更新我的帖子,請看看。 – CoderMusgrove