2013-02-21 94 views
6

जब हटाने दूसरा पिछले तत्व कोई ConcurrentModificationExceptionजावा ConcurrentModificationException

List<String> myList1 = new ArrayList<String>(); 
Collections.addAll(myList1, "str1","str2","str3","str4","str5"); 
for(String element : myList1){//no ConcurrentModificationException here 
if(element.equalsIgnoreCase("str4")) 
    myList1.remove("str4"); 
} 
System.out.println(myList1); 

लेकिन जब निकालने अन्य तत्वों एक ConcurrentModificationException

List<String> myList2 = new ArrayList<String>(); 
Collections.addAll(myList2, "str1","str2","str3","str4","str5"); 
for(String element : myList2){//ConcurrentModificationException here 
if(element.equalsIgnoreCase("str1")) 
    myList2.remove("str1"); 
} 
System.out.println(myList2); 

क्या कारण है वहाँ है?

+3

कृपया प्रश्न सावधानी से पढ़ें। – user1947415

+0

कोड के पहले भाग में भी "थ्रेड में अपवाद" मुख्य "java.util.ConcurrentModificationException" त्रुटि है। जब आप इसे पुन: सक्रिय कर रहे हों तो आप उसी संग्रह को अपडेट नहीं कर सकते। –

+0

मुझे अपवाद क्यों नहीं मिला? क्या आपने कोशिश की? – user1947415

उत्तर

3

मैं एक ही बात दिखाई दे रही है,

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 

public class Launcher 
{ 
    public static void main(String[] args) 
    { 
     doThis(); 
     doThat(); 
    } 

    private static void doThis() 
    { 
     System.out.println("dothis"); 
     try 
     { 
      List<String> myList1 = new ArrayList<String>(); 
      Collections.addAll(myList1, "str1","str2","str3","str4","str5"); 
      for(String element : myList1){//no ConcurrentModificationException here 
      if(element.equalsIgnoreCase("str4")) 
       myList1.remove("str4"); 
      } 
      System.out.println(myList1); 
     } 
     catch(Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 

    private static void doThat() 
    { 
     System.out.println("dothat"); 
     try 
     { 
      List<String> myList2 = new ArrayList<String>(); 
      Collections.addAll(myList2, "str1","str2","str3","str4","str5"); 
      for(String element : myList2){//ConcurrentModificationException here 
      if(element.equalsIgnoreCase("str1")) 
       myList2.remove("str1"); 
      } 
      System.out.println(myList2); 
     } 
     catch(Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 
} 

जो आउटपुट,

dothis 
[str1, str2, str3, str5] 
dothat 
java.util.ConcurrentModificationException 
    at java.util.AbstractList$Itr.checkForComodification(Unknown Source) 
    at java.util.AbstractList$Itr.next(Unknown Source) 
    at com.foo.Launcher.doThat(Launcher.java:41) 
    at com.foo.Launcher.main(Launcher.java:12) 

और मैं the reason पाया है।

+1

हां है। यही मेरा मतलब है दोस्तों। – user1947415

+0

@ user1947415, मैंने एक लिंक जोड़ा है जो उपयोगी साबित हो सकता है। – mre

3

जावा एक मॉडकाउंट (संशोधन गणना) का उपयोग करता है और यह जांचने के लिए अपेक्षित गणना करता है कि सूची में कोई संशोधन है या नहीं।

final void checkForComodification() { 
    if (modCount != expectedModCount) 
     throw new ConcurrentModificationException(); 
} 

दोनों हालत में, modCount निकालने के बाद 6 है, लेकिन expectedModCount समस्या hasNext है 5.

है()।

public boolean hasNext() { 
    return cursor != size; 
} 

सूची एक कर्सर और आकार का उपयोग यह जांचने के लिए करती है कि कोई अगला तत्व है या नहीं। और hasNext() चेकफॉरकोडिफिकेशन से पहले खुश है क्योंकि चेकफोरकोडिफिकेशन() को अगली() विधि में बुलाया जाता है।

public boolean hasNext() { 
     return cursor != size; 
    } 

    @SuppressWarnings("unchecked") 
    public E next() { 
     checkForComodification(); 
     int i = cursor; 
     if (i >= size) 
      throw new NoSuchElementException(); 
     Object[] elementData = ArrayList.this.elementData; 
     if (i >= elementData.length) 
      throw new ConcurrentModificationException(); 
     cursor = i + 1; 
     return (E) elementData[lastRet = i]; 
    } 

तो जब आप दूसरे अंतिम तत्व को हटाते हैं, कर्सर = 4, और आकार = 4 भी। हैनक्स्ट() झूठी वापसी। लूप से बाहर निकलें और परिणाम प्रिंट करें।

+0

लेकिन, मेरा मुद्दा यह है कि कोड के दो टुकड़ों के बीच एकमात्र अंतर यह है कि पहला "str4" को हटा देता है जबकि दूसरा "str1" को हटा देता है। लेकिन, पहला एक सफलतापूर्वक चलाया। दूसरा एक ConcurrentModificationException फेंक देता है। – user1947415

+1

उत्तर अपडेट किया गया। – StarPinkER

+0

यह वही कारण है जब आपने दूसरे तत्व को हटा दिया था। +1 जर्मेन Xu –

-2

यह एक आम तौर पर होने वाली समस्या है। StackOverflow में इसे कवर करने वाले सैकड़ों धागे हैं। आप यहाँ अपने प्रश्न का उत्तर मिल सकते हैं:

How can I iterate over an object while modifying it in Java?

जब आप दूसरे अंतिम तत्व निकाला, hasNext() की जांच में विफल रहता है और पाश यात्रा बंद हो जाता है। जेडीके में ArrayList इटरेटर कोड की जांच करें।

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayList.java#ArrayList.Itr.hasNext%28%29

लेकिन दूसरा तत्व hasNext() चेक गुजरता को हटाने के मामले में और आप अगले() विधि जहां पहली बात यह की जांच करता है ArrayList और इसलिए अपवाद को संशोधन है दर्ज करें। इस कोड की जाँच करें:

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayList.java#ArrayList.Itr.next%28%29

सबसे सुरक्षित तरीका तत्व iterators विधि निकालने का उपयोग कर दूर करने के लिए है।

डीबगर कोड पर कदम उठाने के लिए प्रयास करें, यह कैसे काम करता है इसकी बेहतर समझ के लिए।

+1

आपने मुझे लोगों को नहीं मिला। मैं समझता हूं कि इसके माध्यम से तत्व को हटाने के लिए मुझे इटरेटर का उपयोग करने की आवश्यकता है। लेकिन, मेरा सवाल यह है कि कोड के पहले टुकड़े ने सहमति के रूप में एक ConcurrentModificationException फेंक नहीं दिया था। मैंने परीक्षण किया है यह तब होता है जब आप दूसरे अंतिम तत्व को हटाते हैं। – user1947415

+0

मैंने अपना जवाब अपडेट किया है, इस तरह के मुद्दों को समझने के लिए डीबगर आपकी सबसे अच्छी शर्त –

2

वास्तविक कोड javac for-each के लिए बनाता है कि

Iterator<String> i = myList1.iterator(); 
    while(i.hasNext()) { 
     String element = i.next(); 
     if (element.equalsIgnoreCase("str4")) 
      myList1.remove("str4"); 
    } 

है और इस ArrayList Iterator.hasNext कार्यान्वयन

public boolean hasNext() { 
     return cursor != size; 
    } 

के रूप में हम hasNext() देख समवर्ती संशोधन की जांच नहीं करता इसलिए जब हम निकाल सकते हैं है आखिरी लेकिन एक तत्व लूप समस्या को ध्यान में रखे बिना समाप्त होता है।

असल में यह अजीब बात है कि next() और remove() समवर्ती संशोधन की जांच करें लेकिन hasNext() नहीं है। विफल-तेज इटरेटर को बग का पता लगाना चाहिए, लेकिन हमारी बग अनजान हो गई।