2013-02-26 33 views
11

मैं जब मैं मैं उत्पादन नीचे पाने कोड ऊपर चलाने के दो जावा वर्गसूची ConcurrentModificationException फेंकता है लेकिन सेट ConcurrentModificationException फेंकता नहीं है?

import java.util.*; 

public class ArrayListTest032 { 
    public static void main(String[] ar) { 
     List<String> list = new ArrayList<String>(); 
     list.add("core java"); 
     list.add("php"); 
     list.add("j2ee"); 
     list.add("struts"); 
     list.add("hibernate"); 

     Iterator<String> itr = list.iterator(); 

     while (itr.hasNext()) { 
      System.out.println(itr.next()); 
     } 
     list.remove("php"); 

     while (itr.hasNext()) { 
      System.out.println(itr.next()); 
     } 

    } 
} 

नीचे है।

core java 
php 
j2ee 
struts 
hibernate 

Exception in thread "main" java.util.ConcurrentModificationException 
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372) 
    at java.util.AbstractList$Itr.next(AbstractList.java:343) 
    at ArrayListTest032.main(ArrayListTest032.java:20) 

जो उम्मीद है कि मैं पुनरावृत्ति करते समय सूची को संशोधित कर रहा हूं। लेकिन नीचे जावा वर्ग में एक ही तर्क सेट परिवार द्वारा निष्पादित किया जाता है।

import java.util.*; 

public class HashSetTest021 { 
    public static void main(String[] ar) { 
     Set<String> set = new HashSet<String>(); 
     set.add("core java"); 
     set.add("php"); 
     set.add("j2ee"); 
     set.add("struts"); 
     set.add("hibernate"); 

     Iterator<String> itr = set.iterator(); 

     while (itr.hasNext()) { 
      System.out.println(itr.next()); 
     } 
     set.remove("php"); 

     while (itr.hasNext()) { 
      System.out.println(itr.next()); 
     } 

    } 
} 

और बाहर रखा गया है।

hibernate 
core java 
j2ee 
php 
struts 

किसी भी ConcurrentModificationException नहीं है।

मैं सिर्फ क्यों कोड के एक ही हिस्से list परिवार के मामले में ConcurrentModificationException फेंकता जानना चाहते हैं, लेकिन कोई किसी भी set परिवार के मामले में ConcurrentModificationException है

उत्तर

4

यह कार्यान्वयन में एक अंतर है: सरणी सूची द्वारा लौटाए गए इटरेटर को अंत में स्थित होने पर भी समवर्ती संशोधन का पता चलता है, क्योंकि यह लंबाई की जांच करता है; दूसरी ओर, HashSet, TreeSet और LinkedList के इटरेटर, इस स्थिति का पता नहीं लगाते हैं, क्योंकि वे समवर्ती संशोधन की जांच करने से पहले अंत में स्थित होने की जांच करते हैं। दस्तावेज़ीकरण इटरेटर को समवर्ती संशोधनों पर फेंकने की अनुमति नहीं देता है, इसलिए दोनों दृष्टिकोण वैध हैं।

+0

डेमो फीडल के लिए +1 –

+0

नाइट: ऐरेलिस्ट इटरेटर वास्तव में एक संशोधन गिनती की जांच करता है, लंबाई प्रति लंबाई नहीं, इसलिए यदि आप जोड़ते हैं तो तत्काल एक तत्व को हटा दें, लंबाई को छोड़कर, आपको अभी भी एक समवर्ती मोडिफिकेशन अपवाद प्राप्त होगा। –

1
public static void main(String[] ar) { 
      List<String> list = new ArrayList<String>(); 
      list.add("core java"); 
      list.add("php"); 
      list.add("j2ee"); 
      list.add("struts"); 
      list.add("hibernate"); 

      Iterator<String> itr = list.iterator(); 

      while (itr.hasNext()) { 
       System.out.println(itr.next()); 
      } 
      list.remove("php"); 

      /* while (itr.hasNext()) { 
       System.out.println(itr.next()); 
      }*/ 

     } 

problem in itr object.it holds the list object reference 
+0

तो क्यों सेट अपवाद फेंकता नहीं है। आप आउटपुट स्टैक ट्रेस दोनों से –

+0

दोनों की जांच कर सकते हैं, यह स्पष्ट है कि अपवाद तब आ रहा है जब हम इसे अगले() फ़ंक्शन को कॉलर कहते हैं। यदि आप सोच रहे हैं कि इटरेटर संशोधन के लिए कैसे जांचता है, तो इसका कार्यान्वयन सारसूची वर्ग में मौजूद है जहां एक इंट वेरिएबल मोडकाउंट परिभाषित किया गया है जो सूची आकार को बदल दिया गया है। – Biswajit

5

यह 'की तरह है रेट्रोग्रेड 'व्यवहार, जैसे ही इटरेटर, एक बार पूरी तरह से घुमाए जाने पर, पुन: प्रयोज्य नहीं होते हैं, उर्फ ​​उनकी hasNext विधि सूची के अंत तक पहुंचने पर झूठी वापसी करनी चाहिए।

इस मामले हालांकि, इटरेटर ArrayList.iterator द्वारा लौटाए गए एक आंतरिक कार्यान्वयन वर्ग, कोड के साथ hasNext के लिए इस प्रकार है:

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

तो जब आप अपने दूसरे पाश में hasNext कहते हैं, यह (झूठा) इंगित करता है कि फिर से शुरू करने के लिए और अधिक आइटम हैं, क्योंकि आपने पहले ऑपरेशन के बाद सूची के आकार को बदलने वाले ऑपरेशन को निष्पादित किया था। अर्थात्, आप इसके अंत तक पहुंचने के बाद सूची में आइटमों पर पुनरावृत्ति जारी रखने में सक्षम नहीं होना चाहिए, लेकिन इस कार्यान्वयन के विस्तार के कारण यह आपको दूसरी तरफ लूप के साथ आगे बढ़ने देता है। बेशक, उस बिंदु पर, आपको बैकिंग सूची में किए गए परिवर्तन के कारण एक समवर्ती संशोधन अपवाद मिलता है।

दूसरी ओर, अपने हैश सेट द्वारा प्रयोग किया जाता इटरेटर है अपने hasNext इस प्रकार के रूप में लागू:

public final boolean hasNext() { 
    return next != null; 
} 

इस कार्यान्वयन होता नहीं हैश एक यात्रा के बाद स्थापित करने के लिए किए गए संशोधनों को 'कमजोर' के रूप में होना करने के लिए पूरा हो चुका है, और hasNext विधि बेहतर व्यवहार किया जाता है।

+0

ठीक है और सेट परिवार के मामले में? –

+0

@ रीयल - हैश सेट कार्यान्वयन के लिए अतिरिक्त विवरण। – Perception

2

इटरेटर के लिए JavaDoc पढ़ने से शुरू करें। क्या यह कहीं भी ConcurrentModificationException का उल्लेख करता है?

अब, ConcurrentModificationException के लिए JavaDoc पढ़ा है, और निम्नलिखित पर ध्यान दें (जोर जोड़ा):

यह अपवाद तरीकों से फेंक दिया जा सकता है कि एक वस्तु के समवर्ती संशोधन का पता चला है जब इस तरह के संशोधन नहीं है अनुमत

अब अपने कोड पर बारीकी से नजर डालें। आपके while लूप संग्रह के सभी तत्वों के माध्यम से पुनरावृत्त करता है (भले ही आपके पहले उदाहरण का आउटपुट यह इंगित न करे, जो मुझे बताता है कि या तो आपने आउटपुट संपादित किया है या यह आपका वास्तविक कोड नहीं है)। जब आप तत्व को हटाते हैं, तब पुनरावृत्त करने के लिए कोई और आइटम नहीं होते हैं, इसलिए दूसरा लूप हमेशा बाहर निकलना चाहिए।

तो, निष्कर्ष यह है कि सूची इटरेटर के कार्यान्वयन चुना जब वहाँ पुनरावृत्ति करने के लिए कोई और अधिक तत्व हैं कि कि अपवाद भी फेंक, जबकि सेट इटरेटर के कार्यान्वयन चुना नहीं करने के लिए है है। विनिर्देशों के बाद दोनों मामले पूरी तरह से स्वीकार्य हैं।

+0

मैंने उपरोक्त कोड में एक ही कक्षा को जोड़ा है, आप कोड चला सकते हैं और आउटपुट स्वयं जांच सकते हैं। –

+0

@ रीयल - हाँ, मैंने इसे चलाया, और आउटपुट ने "हाइबरनेट" दिखाया, जो आपकी पोस्टिंग नहीं करता है। लेकिन वास्तव में, अपने शॉर्ट्स को एक मूलभूत टिप्पणी के बारे में मोड़ में लाने के बजाय, आपको वास्तव में मेरे उत्तर की * सामग्री * के बारे में सोचना चाहिए। – parsifal

+0

कोई विचार क्यों इस डिज़ाइन में सूची फेंकता है और सेट को प्राथमिकता दी जाती है? – djechlin

1

हैशसेट एक समवर्ती मोडिफिकेशन एक्सेप्शन फेंक सकता है अगर आप सेटर को छोड़कर सेट पर कुछ भी करते हैं। हालांकि, अगर संभव हो तो पुनरावृत्ति को पूरा करने के लक्ष्य के साथ इटर्टर के तेज़-असफल व्यवहार के आसपास बहुत सारी ह्युरिस्टिक्स हैं। JavaDocs इसके व्यवहार पर बहुत स्पष्ट प्रतीत होता है।

0

सूची के मामले में जब हम इसे पहले लूप इटरेटर itr = set.iterator() के साथ पार करते हैं;

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

पहले जबकि पाश के बाद तो:

while (itr.hasNext()) { 
     System.out.println(itr.next()); 
    } 

कर्सर मूल्य और आकार same.Cursor हो जाएगा चल तत्वों की कुल नहीं के लिए और hashNext अंदर मान() सूची ट्रेवर्सल के लिए विधि के रूप में कोड शामिल कर्सर == आकार। लेकिन सूची आकार से तत्व को हटाने के बाद (मूल आकार -1) बन जाता है। इसलिए अगली देर के लिए लूप यह अंदर और अंदर itr.next() विधि के अंदर जाता है, यह modcount संशोधन के लिए जांचता है और ConcurrentModificationException फेंकता है।

सेट के मामले में यह अगले के लिए चेक करता है! = प्रत्येक itr.hasnext() कॉल के लिए null। और पहले ट्रॉवर्सिंग के बाद लूप अगला शून्य हो जाता है। सेट से तत्व को हटाने से अगले मान को शून्य और itr.hasNext अगला == शून्य के रूप में वापस लौटें और इसलिए यह मॉडकाउंट संशोधन की जांच करने के लिए लूप के अंदर नहीं जाता है। और इसलिए यह ConcurrentModification अपवाद नहीं फेंकता है।

संबंधित मुद्दे