एक लूप में ऑब्जेक्ट्स को हटाते समय, ConcurrentModificationException से बचने के लिए एक संग्रह के माध्यम से Iterating


1194

हम सभी जानते हैं कि आप निम्न कार्य नहीं कर सकते हैं ConcurrentModificationException:

for (Object i : l) {
    if (condition(i)) {
        l.remove(i);
    }
}

लेकिन यह स्पष्ट रूप से कभी-कभी काम करता है, लेकिन हमेशा नहीं। यहाँ कुछ विशिष्ट कोड है:

public static void main(String[] args) {
    Collection<Integer> l = new ArrayList<>();

    for (int i = 0; i < 10; ++i) {
        l.add(4);
        l.add(5);
        l.add(6);
    }

    for (int i : l) {
        if (i == 5) {
            l.remove(i);
        }
    }

    System.out.println(l);
}

यह, निश्चित रूप से, में परिणाम:

Exception in thread "main" java.util.ConcurrentModificationException

हालांकि कई सूत्र यह नहीं कर रहे हैं। वैसे भी।

इस समस्या का सबसे अच्छा समाधान क्या है? मैं इस अपवाद को फेंकने के बिना एक लूप में संग्रह से एक आइटम कैसे निकाल सकता हूं?

मैं भी Collectionयहाँ एक मनमाना उपयोग कर रहा हूँ , जरूरी नहीं कि ArrayListआप पर भरोसा नहीं कर सकते get


पाठकों के लिए ध्यान दें: क्या आपके पास docs.oracle.com/javase/tutorial/collections/interfaces/… का वाचन है , तो आप जो करना चाहते हैं उसे प्राप्त करने का एक आसान तरीका हो सकता है।
GKFX

जवाबों:


1601

Iterator.remove() सुरक्षित है, आप इसे इस तरह उपयोग कर सकते हैं:

List<String> list = new ArrayList<>();

// This is a clever way to create the iterator and call iterator.hasNext() like
// you would do in a while-loop. It would be the same as doing:
//     Iterator<String> iterator = list.iterator();
//     while (iterator.hasNext()) {
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    String string = iterator.next();
    if (string.isEmpty()) {
        // Remove the current element from the iterator and the list.
        iterator.remove();
    }
}

ध्यान दें कि Iterator.remove()पुनरावृत्ति के दौरान एक संग्रह को संशोधित करने का एकमात्र सुरक्षित तरीका है; व्यवहार अप्रभावित है यदि अंतर्निहित संग्रह किसी अन्य तरीके से संशोधित किया गया है जबकि पुनरावृत्ति प्रगति पर है।

स्रोत: docs.oracle> संग्रह इंटरफ़ेस


और इसी तरह, यदि आपके पास एक ListIteratorऔर आइटम जोड़ना चाहते हैं , तो आप उपयोग कर सकते हैं ListIterator#add, उसी कारण से आप उपयोग कर सकते हैं Iterator#remove - यह इसे अनुमति देने के लिए डिज़ाइन किया गया है।


आपके मामले में आपने एक सूची से हटाने की कोशिश की थी, लेकिन इसकी सामग्री को पुनरावृत्त करने की कोशिश putकरते Mapसमय एक ही प्रतिबंध लागू होता है।


19
यदि आप वर्तमान पुनरावृत्ति में दिए गए तत्व के अलावा किसी तत्व को निकालना चाहते हैं तो क्या होगा?
यूजेन

2
आपको इटरमैटर में .remove का उपयोग करना होगा और वह केवल वर्तमान तत्व को हटाने में सक्षम है, इसलिए नहीं :)
बिल K

1
अवगत रहें कि यह समवर्ती LinkedDeque या CopyOnWriteArrayList (मेरे मामले में कम से कम) का उपयोग करने की तुलना में धीमा है
Dan

1
क्या iterator.next()कॉल को लूप में रखना संभव नहीं है ? यदि नहीं, तो कोई क्यों समझा सकता है?
ब्लेक

1
@GonenI यह संग्रह से सभी पुनरावृत्तियों के लिए लागू किया गया है जो अपरिवर्तनीय नहीं हैं। List.addउसी अर्थ में "वैकल्पिक" भी है, लेकिन आप यह नहीं कहेंगे कि सूची में जोड़ना "असुरक्षित" है।
रेडियोडेफ

345

यह काम:

Iterator<Integer> iter = l.iterator();
while (iter.hasNext()) {
    if (iter.next() == 5) {
        iter.remove();
    }
}

मैंने मान लिया कि चूंकि एक फ़ॉरेस्ट लूप पुनरावृत्ति के लिए संश्लिष्ट शर्करा है, इसलिए एक पुनरावृत्ति का उपयोग करने से मदद नहीं मिलेगी ... लेकिन यह आपको यह .remove()कार्यक्षमता प्रदान करता है।


43
foreach पाश है बार-बार दोहराना के लिए वाक्यात्मक चीनी। हालाँकि, जैसा कि आपने बताया, आपको इट्रेटर पर कॉल हटाने की आवश्यकता है - जिसके लिए फ़ॉरच आपको एक्सेस नहीं देता है। इसलिए कारण यह है कि आप एक फॉरेस्ट लूप में नहीं निकाल सकते हैं (भले ही आप वास्तव में हुड के नीचे एक
पुनरावृत्ति

36
उदाहरण के लिए +1 कोड के संदर्भ में iter.remove () का उपयोग करने के लिए, जिसका बिल K का उत्तर [सीधे] नहीं है।
संपादित

202

जावा 8 के साथ आप नई removeIfविधि का उपयोग कर सकते हैं । आपके उदाहरण के लिए लागू:

Collection<Integer> coll = new ArrayList<>();
//populate

coll.removeIf(i -> i == 5);

3
Ooooo! मैं जावा 8 या 9 में कुछ उम्मीद कर रहा था मदद कर सकता है। यह अभी भी बल्कि मेरे लिए क्रिया लगता है, लेकिन मैं अभी भी इसे पसंद करता हूं।
जेम्स टी स्नेल

क्या इस मामले में भी समान () की सिफारिश की जा रही है?
अनमोल गुप्ता

जिस तरह से removeIfउपयोग करता है Iteratorऔर whileपाश। आप इसे जावा 8 पर देख सकते हैंjava.util.Collection.java
omerhakanbilici

3
@omerhakanbilici कुछ कार्यान्वयन जैसे ArrayListप्रदर्शन कारणों से इसे ओवरराइड करते हैं। आप जिसका उल्लेख कर रहे हैं, वह केवल डिफ़ॉल्ट कार्यान्वयन है।
दीदीयर एल

@AnmolGupta: नहीं, equalsयहाँ बिल्कुल भी उपयोग नहीं किया जाता है, इसलिए इसे लागू नहीं किया जाना चाहिए। (लेकिन निश्चित रूप से, यदि आप equalsअपने परीक्षण में उपयोग करते हैं तो इसे उस तरह से लागू करना होगा जैसा आप चाहते हैं।)
Lii

42

चूँकि प्रश्न का उत्तर पहले ही दिया जा चुका है। इसलिए सबसे अच्छा तरीका यह है कि इट्रेटर ऑब्जेक्ट के रिमूव मेथड का उपयोग किया जाए, मैं उस स्थान की बारीकियों में जाऊँगा जहाँ त्रुटि "java.util.ConcurrentModificationException"डाली गई है।

हर संग्रह वर्ग के लिए एक निजी वर्ग जिन्हें इटरेटर इंटरफ़ेस लागू करता है और इस तरह के तरीकों प्रदान करता है next(), remove()और hasNext()

अगले के लिए कोड कुछ इस तरह दिखता है ...

public E next() {
    checkForComodification();
    try {
        E next = get(cursor);
        lastRet = cursor++;
        return next;
    } catch(IndexOutOfBoundsException e) {
        checkForComodification();
        throw new NoSuchElementException();
    }
}

यहाँ विधि checkForComodificationको इस प्रकार लागू किया गया है

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

तो, जैसा कि आप देख सकते हैं, यदि आप स्पष्ट रूप से संग्रह से एक तत्व को निकालने का प्रयास करते हैं। इसका परिणाम modCountअलग-अलग होता है expectedModCount, जिसके परिणामस्वरूप अपवाद होता है ConcurrentModificationException


बहुत ही रोचक। धन्यवाद! मैं अक्सर खुद को हटाने () को कॉल नहीं करता, मैं इसके माध्यम से पुनरावृत्ति के बाद संग्रह को साफ़ करने के पक्ष में हूं। यह कहने के लिए नहीं कि यह एक अच्छा पैटर्न है, बस मैं हाल ही में क्या कर रहा हूं।
जेम्स टी स्नेल

26

आप या तो सीधे इट्टर का उपयोग कर सकते हैं जैसे कि आपने उल्लेख किया है, या फिर एक दूसरे संग्रह को रखें और प्रत्येक आइटम को आप नए संग्रह में निकालना चाहते हैं, फिर अंत में सभी को हटा दें। यह आपको बढ़ी हुई मेमोरी उपयोग और सीपीयू समय की लागत पर प्रत्येक लूप के प्रकार-सुरक्षा का उपयोग करने की अनुमति देता है (जब तक आपके पास वास्तव में बड़ी सूची या वास्तव में पुराना कंप्यूटर न हो, तब तक एक बड़ी समस्या नहीं होनी चाहिए)

public static void main(String[] args)
{
    Collection<Integer> l = new ArrayList<Integer>();
    Collection<Integer> itemsToRemove = new ArrayList<>();
    for (int i=0; i < 10; i++) {
        l.add(Integer.of(4));
        l.add(Integer.of(5));
        l.add(Integer.of(6));
    }
    for (Integer i : l)
    {
        if (i.intValue() == 5) {
            itemsToRemove.add(i);
        }
    }

    l.removeAll(itemsToRemove);
    System.out.println(l);
}

7
यह वही है जो मैं आम तौर पर करता हूं, लेकिन स्पष्ट पुनरावृत्ति एक अधिक अभिमानी समाधान है जो मुझे लगता है।
क्लाउडीउ

1
जब तक आप इट्रेटर के साथ कुछ और नहीं कर रहे हैं, तब तक पर्याप्त करें - इसे उजागर करने से फ़ाइल (।) (प्रति बार दो बार लूप आदि) जैसे काम करना आसान हो जाता है, बड़ी समस्या नहीं है, लेकिन यदि आप कर रहे हैं तो समस्याएँ पैदा कर सकते हैं। प्रविष्टियों को हटाने के लिए एक सूची के माध्यम से चलने की तुलना में अधिक जटिल कुछ भी नहीं है।
रोडियोक्लोअन

@RodeoClown: मूल प्रश्न में, क्लाउडीयू संग्रह से हटा रहा है, न कि पुनरावृत्ति।
मैट बी

1
इटरेटर को हटाने से अंतर्निहित संग्रह से हटा दिया जाता है ... लेकिन जो मैं पिछले टिप्पणी में कह रहा था वह यह है कि यदि आप कुछ अधिक जटिल कर रहे हैं तो लूप में डिलीट की तलाश में है (जैसे कि सही डेटा को संसाधित करना) इटरेटर का उपयोग करके कुछ बना सकते हैं त्रुटियों को बनाना आसान है।
रोडियोक्लब

यदि यह एक साधारण डिलीट वैल्यू है जिसकी जरूरत नहीं है और लूप केवल एक काम कर रहा है, तो सीधे इटरेटर का उपयोग करके .remove () बिल्कुल ठीक है।
रोडियोक्लब

17

ऐसे मामलों में पीछे जाने के लिए एक आम चाल है (है?):

for(int i = l.size() - 1; i >= 0; i --) {
  if (l.get(i) == 5) {
    l.remove(i);
  }
}

उस ने कहा, मैं खुश हूं कि आपके पास जावा 8, जैसे removeIfया filterधाराओं में बेहतर तरीके हैं।


2
यह एक अच्छी चाल है। लेकिन यह सेट की तरह गैर-अनुक्रमित संग्रह पर काम नहीं करेगा, और यह लिंक की गई सूचियों पर वास्तव में धीमा होगा।
क्लॉडिउ

@ कलुआडु हां, यह निश्चित रूप से सिर्फ ArrayListइसी तरह के संग्रह के लिए है।
लैंडेई

मैं एक ArrayList का उपयोग कर रहा हूं, यह पूरी तरह से काम करता है, धन्यवाद।
StarSweeper

2
अनुक्रमित महान हैं। यदि यह इतना सामान्य है तो आप इसका उपयोग क्यों नहीं करते for(int i = l.size(); i-->0;) {?
जॉन


12

ग्रहण संग्रह के साथ , MutableCollectionremoveIf पर परिभाषित विधि काम करेगी:

MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.lessThan(3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);

जावा 8 लैंबडा सिंटैक्स के साथ इस प्रकार लिखा जा सकता है:

MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.cast(integer -> integer < 3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);

यहां कॉल Predicates.cast()आवश्यक है क्योंकि जावा 8 में इंटरफ़ेस removeIfपर एक डिफ़ॉल्ट विधि जोड़ी गई थी java.util.Collection

नोट: मैं एक्लिप्स कलेक्शंस के लिए कमिट हूं ।


10

मौजूदा सूची की एक प्रति बनाएँ और नई प्रति पर पुनरावृति करें।

for (String str : new ArrayList<String>(listOfStr))     
{
    listOfStr.remove(/* object reference or index */);
}

19
प्रतिलिपि बनाना संसाधनों की बर्बादी जैसा लगता है।
अंटीजी

3
@Antzi सूची के आकार और वस्तुओं के घनत्व पर निर्भर करती है। अभी भी एक मूल्यवान और वैध समाधान है।
MRE

मैं इस विधि का उपयोग कर रहा हूं। यह थोड़ा अधिक संसाधन लेता है, लेकिन बहुत अधिक लचीला और स्पष्ट है।
ताओ झांग

यह एक अच्छा समाधान है जब आप स्वयं लूप के अंदर वस्तुओं को हटाने का इरादा नहीं रखते हैं, लेकिन वे अन्य थ्रेड्स (जैसे नेटवर्क संचालन डेटा को अपडेट करने) से "बेतरतीब ढंग से" हटाए जाते हैं। यदि आप अपने आप को इन प्रतियों को करते हुए पाते हैं तो एक जावा कार्यान्वयन भी ठीक से कर रहा है: docs.oracle.com/javase/8/docs/api/java/util/concurrent/…
A1m 26/19

8

लोग यह दावा कर रहे हैं कि एक फॉर्च्यून लूप द्वारा पुनरावृत्त होने वाले संग्रह से हटाया नहीं जा सकता है । मैं सिर्फ यह बताना चाहता था कि यह तकनीकी रूप से गलत है और इसका ठीक-ठीक वर्णन है (मुझे पता है कि ओपी का प्रश्न इतना उन्नत है कि इसे जानने के लिए उस धारणा के पीछे का कोड):

for (TouchableObj obj : untouchedSet) {  // <--- This is where ConcurrentModificationException strikes
    if (obj.isTouched()) {
        untouchedSet.remove(obj);
        touchedSt.add(obj);
        break;  // this is key to avoiding returning to the foreach
    }
}

ऐसा नहीं है कि आप इसे पुनरावृत्त से हटा नहीं सकते हैं, Colletionबल्कि आप एक बार ऐसा करने के बाद पुनरावृति जारी नहीं रख सकते हैं। इसलिए breakऊपर दिए गए कोड में।

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


8

पाश के लिए एक पारंपरिक के साथ

ArrayList<String> myArray = new ArrayList<>();

for (int i = 0; i < myArray.size(); ) {
    String text = myArray.get(i);
    if (someCondition(text))
        myArray.remove(i);
    else
        i++;   
}

आह, तो यह वास्तव में सिर्फ बढ़ाया -लूप है कि अपवाद फेंकता है।
cellepo

एफडब्ल्यूआईडब्ल्यू - समान कोड i++लूप बॉडी के बजाय लूप गार्ड में वृद्धि के बाद भी काम करेगा ।
cellepo

सुधार ^: यह है कि अगर i++वेतन वृद्धि सशर्त नहीं थे - अब मैं देख रहा हूं कि आप इसे शरीर में क्यों करते हैं :)
cellepo

2

A ListIteratorआपको सूची में आइटम जोड़ने या निकालने की अनुमति देता है। मान लीजिए कि आपके पास Carवस्तुओं की एक सूची है :

List<Car> cars = ArrayList<>();
// add cars here...

for (ListIterator<Car> carIterator = cars.listIterator();  carIterator.hasNext(); )
{
   if (<some-condition>)
   { 
      carIterator().remove()
   }
   else if (<some-other-condition>)
   { 
      carIterator().add(aNewCar);
   }
}

ListIterator इंटरफ़ेस (Iterator का विस्तार) में अतिरिक्त विधियाँ दिलचस्प हैं - विशेष रूप से इसकी previousविधि।
cellepo

1

ऊपर की समस्या के लिए मेरे पास एक सुझाव है। माध्यमिक सूची या किसी अतिरिक्त समय की आवश्यकता नहीं है। कृपया एक उदाहरण खोजें जो समान सामान लेकिन अलग तरीके से करेगा।

//"list" is ArrayList<Object>
//"state" is some boolean variable, which when set to true, Object will be removed from the list
int index = 0;
while(index < list.size()) {
    Object r = list.get(index);
    if( state ) {
        list.remove(index);
        index = 0;
        continue;
    }
    index += 1;
}

यह कॉनसेन्ट एक्सेप्शन से बचना होगा।


1
प्रश्न स्पष्ट रूप से बताता है, कि ओपी का उपयोग करना आवश्यक नहीं है ArrayListऔर इस तरह भरोसा नहीं कर सकता get()। अन्यथा शायद एक अच्छा दृष्टिकोण है, हालांकि।
kaskelotti

(स्पष्टता ^) ओपी एक मनमाना उपयोग कर रहा है Collection- Collectionइंटरफ़ेस शामिल नहीं है get। (हालांकि एफडब्ल्यूआईडब्ल्यू Listइंटरफेस में ' गेट ' शामिल है)।
cellepo

मैंने अभी-अभी एक अलग, अधिक विस्तृत उत्तर भी whileजोड़ा है List। लेकिन इस उत्तर के लिए +1 क्योंकि यह पहले आया था।
cellepo

1

ConcurrentHashMap या ConcurrentLinkedQueue या ConcurrentSkipListMap एक और विकल्प हो सकता है, क्योंकि वे कभी भी किसी भी समसामयिकीकरण अपवाद को नहीं फेंकेंगे, भले ही आप आइटम निकालें या जोड़ें।


हां, और ध्यान दें कि वे सभी java.util.concurrentपैकेज में हैं। उस पैकेज के कुछ अन्य समान / समान-उपयोग-मामले वर्ग हैं CopyOnWriteArrayList और CopyOnWriteArraySet [लेकिन उन तक सीमित नहीं हैं]।
cellepo

वास्तव में, मैंने अभी सीखा कि यद्यपि वे डेटा संरचना ऑब्जेक्ट ऑब्जेक्ट से बचते हैं ConcurrentModificationException , उन्हें एन्हांस्ड -लूप में उपयोग करना अभी भी अनुक्रमण समस्याओं का कारण बन सकता है (यानी: अभी भी तत्वों को छोड़ रहा है, या IndexOutOfBoundsException...)
cellepo

1

मुझे पता है कि यह प्रश्न जावा 8 के बारे में बहुत पुराना है, लेकिन जावा 8 का उपयोग करने वालों के लिए आप आसानी से रिमूव () का उपयोग कर सकते हैं:

Collection<Integer> l = new ArrayList<Integer>();

for (int i=0; i < 10; ++i) {
    l.add(new Integer(4));
    l.add(new Integer(5));
    l.add(new Integer(6));
}

l.removeIf(i -> i.intValue() == 5);

1

दूसरा तरीका यह है कि आप अपने व्यूअर की एक प्रति बनाएँ:

List<Object> l = ...

List<Object> iterationList = ImmutableList.copyOf(l);

for (Object i : iterationList) {
    if (condition(i)) {
        l.remove(i);
    }
}

नोट: वस्तु के बजाय iएक नहीं है index। शायद फोन objकरना ज्यादा सही होगा।
12

1

सबसे अच्छा तरीका (अनुशंसित) java.util.Concurrent पैकेज का उपयोग है। इस पैकेज का उपयोग करके आप आसानी से इस अपवाद से बच सकते हैं। संशोधित कोड देखें

public static void main(String[] args) {
    Collection<Integer> l = new CopyOnWriteArrayList<Integer>();

    for (int i=0; i < 10; ++i) {
        l.add(new Integer(4));
        l.add(new Integer(5));
        l.add(new Integer(6));
    }

    for (Integer i : l) {
        if (i.intValue() == 5) {
            l.remove(i);
        }
    }

    System.out.println(l);
}

0

ArrayList के मामले में : निकालें (int index) - यदि (इंडेक्स अंतिम तत्व की स्थिति है) तो इसके बिना बच जाता है System.arraycopy()और इसके लिए समय नहीं लगता है।

अरैस्कोपी समय बढ़ जाता है अगर (सूचकांक कम हो जाता है), वैसे सूची के तत्व भी घट जाते हैं!

सबसे अच्छा प्रभावी तरीका है- अवरोही क्रम में इसके तत्वों को हटाना: while(list.size()>0)list.remove(list.size()-1);// O (1) while(list.size()>0)list.remove(0);// O लेता है (भाज्य (n))

//region prepare data
ArrayList<Integer> ints = new ArrayList<Integer>();
ArrayList<Integer> toRemove = new ArrayList<Integer>();
Random rdm = new Random();
long millis;
for (int i = 0; i < 100000; i++) {
    Integer integer = rdm.nextInt();
    ints.add(integer);
}
ArrayList<Integer> intsForIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsDescIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsIterator = new ArrayList<Integer>(ints);
//endregion

// region for index
millis = System.currentTimeMillis();
for (int i = 0; i < intsForIndex.size(); i++) 
   if (intsForIndex.get(i) % 2 == 0) intsForIndex.remove(i--);
System.out.println(System.currentTimeMillis() - millis);
// endregion

// region for index desc
millis = System.currentTimeMillis();
for (int i = intsDescIndex.size() - 1; i >= 0; i--) 
   if (intsDescIndex.get(i) % 2 == 0) intsDescIndex.remove(i);
System.out.println(System.currentTimeMillis() - millis);
//endregion

// region iterator
millis = System.currentTimeMillis();
for (Iterator<Integer> iterator = intsIterator.iterator(); iterator.hasNext(); )
    if (iterator.next() % 2 == 0) iterator.remove();
System.out.println(System.currentTimeMillis() - millis);
//endregion
  • इंडेक्स लूप के लिए: 1090 मिसे
  • डीईसी इंडेक्स के लिए: 519 मिसे --- सर्वश्रेष्ठ
  • सूचना के लिए: 1043 मिसे

0
for (Integer i : l)
{
    if (i.intValue() == 5){
            itemsToRemove.add(i);
            break;
    }
}

यदि आप आंतरिक itter.next () कॉल को छोड़ते हैं, तो सूची से तत्व को हटाने के बाद यह पकड़ है। यह अभी भी काम करता है! हालांकि मैं इस तरह कोड को लिखने का प्रस्ताव नहीं करता, इसके पीछे की अवधारणा को समझने में मदद करता है :-)

चीयर्स!


0

धागा सुरक्षित संग्रह संशोधन का उदाहरण:

public class Example {
    private final List<String> queue = Collections.synchronizedList(new ArrayList<String>());

    public void removeFromQueue() {
        synchronized (queue) {
            Iterator<String> iterator = queue.iterator();
            String string = iterator.next();
            if (string.isEmpty()) {
                iterator.remove();
            }
        }
    }
}

0

मुझे पता है कि यह सवाल केवल ए Collectionऔर अधिक विशेष रूप से किसी भी नहीं मानता है List। लेकिन इस सवाल का जो वास्तव में एक साथ काम कर रहे लोगों के लिए पढ़ने Listसंदर्भ, आप बच सकते हैं ConcurrentModificationExceptionएक साथ while(जबकि यह भीतर संशोधित) -loop बजाय अगर आप बचना चाहते हैंIterator (या तो अगर आप सामान्य रूप में यह बचने के लिए, या वह विशेष रूप से बचने के प्राप्त करने के लिए करना चाहते हैं प्रत्येक तत्व पर स्टार्ट-टू-एंड स्टॉप से ​​अलग एक लूपिंग ऑर्डर [जो मुझे लगता है कि केवल वही ऑर्डर है जो Iteratorखुद कर सकता है]):

* अपडेट: नीचे दिए गए टिप्पणियों को देखें जो स्पष्ट करते हैं कि पारंपरिक -प्रो-लूप के साथ सादृश्य भी प्राप्त करने योग्य है ।

final List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; ++i){
    list.add(i);
}

int i = 1;
while(i < list.size()){
    if(list.get(i) % 2 == 0){
        list.remove(i++);

    } else {
        i += 2;
    }
}

उस कोड से कोई ConcurrentModificationException नहीं है।

वहाँ हम देखते हैं कि शुरुआत में लूपिंग शुरू नहीं होती है, और हर तत्व पर नहीं रुकती है (जो मुझे लगता Iteratorहै कि खुद नहीं कर सकते हैं)।

FWIW हम भी देखें getपर बुलाया जा रहा है list, जो नहीं किया जा सकता है अगर अपने संदर्भ केवल था Collection(अधिक विशिष्ट के बजाय Listका प्रकार Collection) - Listइंटरफ़ेस शामिल हैं get, लेकिन Collectionइंटरफ़ेस नहीं करता है। यदि उस अंतर के लिए नहीं है, तो listसंदर्भ इसके बजाय Collection[और इसलिए तकनीकी रूप से यह उत्तर फिर एक स्पर्शरेखा उत्तर के बजाय एक प्रत्यक्ष उत्तर हो सकता है]।

FWIWW एक ही कोड अभी भी काम करने के बाद हर तत्व (जैसे Iteratorऑर्डर) पर स्टॉप पर शुरू करने के लिए संशोधित करने के बाद काम करता है :

final List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; ++i){
    list.add(i);
}

int i = 0;
while(i < list.size()){
    if(list.get(i) % 2 == 0){
        list.remove(i);

    } else {
        ++i;
    }
}

हालांकि, हटाने के लिए अभी भी संकेत की बहुत सावधानीपूर्वक गणना की आवश्यकता है।
वनक्रीचर

इसके अलावा, यह इस उत्तर stackoverflow.com/a/43441822/2308683
OneCricketeer

जानकर अच्छा लगा - धन्यवाद! यही कारण है कि अन्य उत्तर मुझे समझते हैं कि यह है की मदद से बढ़ाया -किसी लूप कि फेंक ConcurrentModificationException, लेकिन नहीं पारंपरिक -किसी लूप (जो अन्य उत्तर का उपयोग करता है) - कि पहले साकार नहीं क्यों मैं इस उत्तर लिखने के लिए प्रेरित किया गया था (ग़लती है मैं तब सोचा कि यह सभी -छोरों के लिए है जो अपवाद को फेंक देंगे)।
cellepo

0

एक समाधान सूची को घुमाने के लिए हो सकता है और पहले तत्व को समवर्ती को हटाने के लिए हटाया जा सकता है

int n = list.size();
for(int j=0;j<n;j++){
    //you can also put a condition before remove
    list.remove(0);
    Collections.rotate(list, 1);
}
Collections.rotate(list, -1);

0

इसे आज़माएँ (सूची में सभी तत्वों को निकालता है जो बराबर i):

for (Object i : l) {
    if (condition(i)) {
        l = (l.stream().filter((a) -> a != i)).collect(Collectors.toList());
    }
}

-2

यह सबसे अच्छा तरीका नहीं हो सकता है, लेकिन अधिकांश छोटे मामलों के लिए यह स्वीकार्य होना चाहिए:

"एक दूसरा खाली-सरणी बनाएं और केवल वही जोड़ें जो आप रखना चाहते हैं"

मुझे यह याद नहीं है कि मैंने इसे कहां से पढ़ा है ... औचित्य के लिए मैं इस विकी को आशा में रखूंगा कि कोई इसे पाता है या सिर्फ रेप नहीं करता है जिसके लिए मैं योग्य नहीं हूं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.