আমি কেন এই উদাহরণে java.util.ConcurrentModificationsException পাচ্ছি না?


176

দ্রষ্টব্য: আমি Iterator#remove()পদ্ধতি সম্পর্কে সচেতন ।

নিম্নলিখিত কোড নমুনা, আমি বুঝতে পারে না কেন List.removemainপদ্ধতি ছোঁড়ার ConcurrentModificationExceptionকিন্তু নাremoveপদ্ধতি।

public class RemoveListElementDemo {    
    private static final List<Integer> integerList;

    static {
        integerList = new ArrayList<Integer>();
        integerList.add(1);
        integerList.add(2);
        integerList.add(3);
    }

    public static void remove(Integer toRemove) {
        for(Integer integer : integerList) {
            if(integer.equals(toRemove)) {                
                integerList.remove(integer);
            }
        }
    }

    public static void main(String... args) {                
        remove(Integer.valueOf(2));

        Integer toRemove = Integer.valueOf(3);
        for(Integer integer : integerList) {
            if(integer.equals(toRemove)) {                
                integerList.remove(integer);
            }
        }
    }
}

3
তালিকার পুনরাবৃত্তির সময় তালিকা থেকে উপাদানকে সরিয়ে ফেলার একমাত্র নিরাপদ উপায় ব্যবহার করা Iterator#remove()। কেন আপনি এইভাবে এটি করছেন?
ম্যাট বল

@ ম্যাটবাল: আমি এখানে দেখার কারণটি কী হতে পারে তা দেখার চেষ্টা করছিলাম। কারণ, এটি উভয় পদ্ধতিতে একই "লুপের জন্য বর্ধিত" তবে একটি নিক্ষেপ করে ConcurrentModificationExceptionএবং অন্যটি তা করে না।
ভেশে গুরুং

আপনি যে উপাদানটি সরিয়েছেন তার মধ্যে একটি পার্থক্য রয়েছে the পদ্ধতিতে আপনি 'মাঝারি উপাদানটি' মুছুন। প্রধান আপনি শেষ অপসারণ। আপনি যদি নম্বরগুলি অদলবদল করেন তবে আপনার পদ্ধতিতে ব্যতিক্রম পাবেন। এখনও কেন তা নিশ্চিত নয়।
বেন ভ্যান গম্পেল

আমার একই ধরণের সমস্যা হয়েছিল, যখন আমার লুপটি পুনরুক্ত করে এমন একটি অবস্থানও পুনরুক্ত করে যা আমি লুপের কোনও আইটেম সরিয়ে নেওয়ার পরে উপস্থিত ছিল না। আমি কেবল লুপটিতে একটি যুক্ত return;করে এটি ঠিক করেছি।
ফ্র্যাঙ্ক 17

জাভা 8 অ্যান্ড্রয়েডে, সর্বশেষটি ছাড়া অন্য উপাদানগুলি সরিয়ে ফেলা সমকালীন মড্যালিফিকেশন এক্সেক্সেশনকে অনুরোধ করবে। সুতরাং আপনার ক্ষেত্রে, অপসারণ ফাংশনটি এমন একটি ব্যতিক্রম পাবে যা আপনি পূর্বে পর্যবেক্ষণ করেছেন opposite
gonglong

উত্তর:


262

এখানে কেন: জাভাডোকে যেমন বলা হয়েছে:

এই শ্রেণীর পুনরায় এবং পুনরায় তালিকার দ্বারা প্রত্যাবর্তিত আইট্রেটারগুলি ব্যর্থ দ্রুত: যদি পুনরুক্তিটি তৈরির পরে তালিকাটি যে কোনও সময়ে কাঠামোগতভাবে সংশোধন করা হয় তবে পুনরাবৃত্তকারীটির নিজস্ব অপসারণ বা পদ্ধতিগুলি বাদ দিয়ে যেকোন উপায়ে পুনরুক্তিটি একটি সমকালীন মডেফিকেশন এক্সেক্সশন নিক্ষেপ করবে।

এই চেকটি next()পুনরাবৃত্তির পদ্ধতিতে করা হয় (যেমন আপনি স্ট্যাকট্রেস দ্বারা দেখতে পারেন)। তবে সঠিকভাবে পৌঁছে দিলে আমরা next()পদ্ধতিটিতে পৌঁছে যাব hasNext(), যা প্রত্যেকের জন্য সীমানা পূরণ হয়েছে কিনা তা যাচাই করার জন্য ডাকা হয়। আপনার অপসারণের পদ্ধতিতে, যখন hasNext()এটি অন্য উপাদানটিকে ফেরত দেওয়ার দরকার রয়েছে কিনা তা পরীক্ষা করে দেখবে যে এটি দুটি উপাদানকে ফিরিয়ে দিয়েছে এবং এখন একটি উপাদান সরানোর পরে তালিকায় কেবলমাত্র দুটি উপাদান রয়েছে। সুতরাং সমস্ত peachy এবং আমরা পুনরাবৃত্তি সঙ্গে সম্পন্ন করা হয়। একযোগে পরিবর্তনগুলির জন্য চেকটি ঘটে না, কারণ এটি এমন next()পদ্ধতিতে করা হয় যা কখনই ডাকা হয় না।

এরপরে আমরা দ্বিতীয় লুপটিতে পৌঁছে যাই। আমরা দ্বিতীয় নম্বরটি সরিয়ে দেওয়ার পরে হ্যান্সেক্সট পদ্ধতিটি আরও মানগুলি ফিরিয়ে দিতে পারে কিনা তা আবার পরীক্ষা করবে। এটি ইতিমধ্যে দুটি মান ফিরিয়ে দিয়েছে, তবে তালিকায় এখন কেবলমাত্র একটি রয়েছে। তবে এখানে কোডটি হ'ল:

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

1! = 2, সুতরাং আমরা next()পদ্ধতিটি অব্যাহত রাখি , যা এখন বুঝতে পারে যে কেউ তালিকার সাথে বিশৃঙ্খলা করছে এবং ব্যতিক্রমটিকে সরিয়ে দেয়।

আশা করি এটি আপনার প্রশ্ন সরিয়ে দেয়।

সারসংক্ষেপ

List.remove()ConcurrentModificationExceptionএটি তালিকা থেকে দ্বিতীয় শেষ উপাদানটি সরিয়ে ফেললে নিক্ষেপ করবে না ।


5
@ পুশি: কেবলমাত্র এমন উত্তর যা মনে হচ্ছে যে প্রশ্নটি আসলে যা জিজ্ঞাসা করছে তার উত্তর বলে মনে হচ্ছে এবং ব্যাখ্যাটি ভাল। আমি এই উত্তরটি গ্রহণ করছি এবং +1ও করছি। ধন্যবাদ।
ভেশে গুরুং

42

Collectionযদি প্রযোজ্য হয় তবে এটির কোনও হস্তান্তর করার একটি উপায় (কোনও সংগ্রহ নিজেই নয়) এর অনুলিপি থেকে কিছু সরিয়ে ফেলার জন্য । Cloneমূল সংগ্রহটি এটির মাধ্যমে একটি অনুলিপি তৈরি করতে Constructor

এই ব্যতিক্রমটি এমন পদ্ধতিগুলির দ্বারা ছুঁড়ে দেওয়া যেতে পারে যেগুলি যখন এই জাতীয় পরিবর্তন অনুমোদিত না হয় তখন কোনও সামগ্রীর একযোগে সংশোধন করে।

আপনার নির্দিষ্ট ক্ষেত্রে, প্রথমে, আমি মনে করি না finalআপনি অতীতের ঘোষণাপত্রটি তালিকাকে সংশোধন করতে চান বলে বিবেচনা করে যাওয়া কোনও উপায়

private static final List<Integer> integerList;

মূল তালিকার পরিবর্তে একটি অনুলিপি পরিবর্তন করার বিষয়টিও বিবেচনা করুন।

List<Integer> copy = new ArrayList<Integer>(integerList);

for(Integer integer : integerList) {
    if(integer.equals(remove)) {                
        copy.remove(integer);
    }
}

14

আইটেমগুলি সরানোর সময় ফরোয়ার্ড / পুনরুক্তি পদ্ধতি কার্যকর হয় না। আপনি ত্রুটি ছাড়াই উপাদানটি সরিয়ে ফেলতে পারেন, তবে আপনি মুছে ফেলা আইটেমগুলিতে অ্যাক্সেস করার চেষ্টা করলে রানটাইম ত্রুটি পাবেন। আপনি পুনরুক্তি ব্যবহার করতে পারবেন না কারণ পুশির মতো দেখায় এটি কনকন্টেরমোডাইফিকেশন এক্সসেপশন ঘটায়, সুতরাং পরিবর্তে লুপের জন্য একটি নিয়মিত ব্যবহার করুন, তবে এর মধ্য দিয়ে পিছনে যান।

List<Integer> integerList;
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);

int size= integerList.size();

//Item to remove
Integer remove = Integer.valueOf(3);

একটি সমাধান:

আপনি যদি কোনও তালিকার উপাদান সরিয়ে ফেলতে চলেছেন তবে বিপরীত ক্রমে অ্যারেটি অতিক্রম করুন। কেবল তালিকার পিছনে গিয়ে আপনি যে আইটেমটি সরিয়ে ফেলা হয়েছে তা পরিদর্শন করা এড়িয়ে যান, যা ব্যতিক্রম সরিয়ে দেয়।

//To remove items from the list, start from the end and go backwards through the arrayList
//This way if we remove one from the beginning as we go through, then we will avoid getting a runtime error
//for java.lang.IndexOutOfBoundsException or java.util.ConcurrentModificationException as when we used the iterator
for (int i=size-1; i> -1; i--) {
    if (integerList.get(i).equals(remove) ) {
        integerList.remove(i);
    }
}

দারুণ বুদ্ধি !
dobrivoje

7

এই স্নিপেটটি সর্বদা একটি সমকালীন মডেলিংএক্সেপশন নিক্ষেপ করবে ।

নিয়মটি হ'ল "আপনি কোনও আইট্রেটর ব্যবহার করে এর উপর পুনরাবৃত্তি করার সময় (তালিকা থেকে উপাদানগুলি যুক্ত বা সরিয়ে ফেলতে পারবেন না) (যা আপনি যখন প্রতিটি লুপ ব্যবহার করেন তখন ঘটে)"।

JavaDocs:

এই শ্রেণীর পুনরায় এবং পুনরায় তালিকার দ্বারা প্রত্যাবর্তিত আইট্রেটারগুলি ব্যর্থ দ্রুত: যদি পুনরুক্তিটি তৈরির পরে তালিকাটি যে কোনও সময়ে কাঠামোগতভাবে সংশোধন করা হয় তবে পুনরাবৃত্তকারীটির নিজস্ব অপসারণ বা পদ্ধতিগুলি বাদ দিয়ে যেকোন উপায়ে পুনরুক্তিটি একটি সমকালীন মডেফিকেশন এক্সেক্সশন নিক্ষেপ করবে।

সুতরাং আপনি যদি তালিকাটি (বা সাধারণ কোনও সংগ্রহ) সংশোধন করতে চান তবে পুনরাবৃত্তকারীটি ব্যবহার করুন, কারণ এটি পরিবর্তনগুলি সম্পর্কে অবগত এবং তাই সেগুলি সঠিকভাবে পরিচালনা করা হবে।

আশাকরি এটা সাহায্য করবে.


3
ওপি স্পষ্টভাবে বলেছে যে কোনও একটি লুপ তার ব্যতিক্রম ছুঁড়ে না এবং জিজ্ঞাসাবাদককে কেন এটি হয়েছিল happened
madth3

'জিজ্ঞাসাবাদী' বলতে কী বোঝ?
ভূষণ

4

আমারও একই সমস্যা ছিল তবে আমি পুনরাবৃত্ত তালিকায় একটি উপাদান যুক্ত করছি। আমি এটি এইভাবে তৈরি

public static void remove(Integer remove) {
    for(int i=0; i<integerList.size(); i++) {
        //here is maybe fine to deal with integerList.get(i)==null
        if(integerList.get(i).equals(remove)) {                
            integerList.remove(i);
        }
    }
}

এখন সবকিছু ঠিকঠাক হয়ে গেছে কারণ আপনি নিজের তালিকার উপরে কোনও পুনরাবৃত্তকারী তৈরি করেন না, আপনি "ম্যানুয়ালি" এটিকে পুনরাবৃত্তি করেন। এবং শর্তটি i < integerList.size()আপনাকে কখনই বোকা বানায় না কারণ আপনি যখন তালিকা হ্রাস / বর্ধনের তালিকা আকারের মধ্যে কিছু সরিয়ে / যুক্ত করেন ..

আশা করি এটি সাহায্য করবে, আমার জন্য এটি সমাধান ছিল।


এটা সত্য নয়! প্রমাণ: ফলাফলটি দেখতে এই স্নিপেটটি চালান: পাবলিক স্ট্যাটিক শূন্য মূল (স্ট্রিং ... আরগস) {তালিকা <স্ট্রিং> listOfBooks = নতুন অ্যারেলিস্ট <> (); listOfBooks.add ("কোড সম্পূর্ণ"); listOfBooks.add ("কোড 22"); listOfBooks.add ("22 কার্যকর"); listOfBooks.add ("নেটবিস 33"); System.err.println ("মুছে ফেলার আগে:" + listOfBooks); (int সূচী = 0; সূচক <listOfBooks.size (); সূচক ++) {যদি (listOfBooks.get (সূচক)। কন্টেন্টস ("22")) {listOfBooks.remove (সূচক); ।। System.err.println ("মুছে ফেলার পরে:" + listOfBooks); }
dobrivoje

1

আপনি যদি অনুলিপি-অনুলিপি সংগ্রহগুলি ব্যবহার করেন তবে এটি কার্যকর হবে; তবে আপনি যখন list.iterator () ব্যবহার করেন, প্রত্যাবর্তিত ইট্রেটর সর্বদা উপাদানগুলির সংগ্রহকে সেইরকম উল্লেখ করবে যেমনটি ছিল (নীচে হিসাবে) list.iterator () বলা হয়েছিল, এমনকি অন্য থ্রেডে সংগ্রহটি পরিবর্তন করে। কোনও অনুলিপি পদ্ধতি কোনও অনুলিপি-ভিত্তিক আইট্রেটার বা লিস্টিএটরেটর (যেমন অ্যাড, সেট, বা অপসারণ) এর নামে ডাকা হয় একটি অসমর্থিত অপারেটিং এক্সেক্সশন নিক্ষেপ করবে।

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class RemoveListElementDemo {    
    private static final List<Integer> integerList;

    static {
        integerList = new CopyOnWriteArrayList<>();
        integerList.add(1);
        integerList.add(2);
        integerList.add(3);
    }

    public static void remove(Integer remove) {
        for(Integer integer : integerList) {
            if(integer.equals(remove)) {                
                integerList.remove(integer);
            }
        }
    }

    public static void main(String... args) {                
        remove(Integer.valueOf(2));

        Integer remove = Integer.valueOf(3);
        for(Integer integer : integerList) {
            if(integer.equals(remove)) {                
                integerList.remove(integer);
            }
        }
    }
}

0

এটি জাভা 1.6 এ সূক্ষ্ম রান করে

j% জাভ্যাক সরানলিস্টিলিটমেন্ট ডেমো.জভা
~% জাভা সরানলিস্টলেমেন্টডেমো
~% বিড়াল সরানলিস্টিলিটমেন্ট ডেমো.জভা

import java.util.*;
public class RemoveListElementDemo {    
    private static final List<Integer> integerList;

    static {
        integerList = new ArrayList<Integer>();
        integerList.add(1);
        integerList.add(2);
        integerList.add(3);
    }

    public static void remove(Integer remove) {
        for(Integer integer : integerList) {
            if(integer.equals(remove)) {                
                integerList.remove(integer);
            }
        }
    }

    public static void main(String... args) {                
        remove(Integer.valueOf(2));

        Integer remove = Integer.valueOf(3);
        for(Integer integer : integerList) {
            if(integer.equals(remove)) {                
                integerList.remove(integer);
            }
        }
    }
}

~%



হুম ... আপনার আলাদা প্রয়োগ হতে পারে। তবে নির্দিষ্টকরণ অনুসারে এটি করার কথা, আইএমও। @ পুষীর উত্তর দেখুন।
ভেশে গুরুং

দুর্ভাগ্যক্রমে, আইডি জাভা 1.8 এ নেই
dobrivoje

0

আমার ক্ষেত্রে আমি এটি এটি করেছিলাম:

int cursor = 0;
do {
    if (integer.equals(remove))
        integerList.remove(cursor);
    else cursor++;
} while (cursor != integerList.size());

0

ইটারেটর পরিবর্তন for eachমধ্যে for loopসমাধানের জন্য।

এবং কারণটি হ'ল:

এই শ্রেণীর পুনরায় এবং পুনরায় তালিকার দ্বারা প্রত্যাবর্তিত আইট্রেটারগুলি ব্যর্থ দ্রুত: যদি পুনরুক্তিটি তৈরির পরে তালিকাটি যে কোনও সময়ে কাঠামোগতভাবে সংশোধন করা হয় তবে পুনরাবৃত্তকারীটির নিজস্ব অপসারণ বা পদ্ধতিগুলি বাদ দিয়ে যেকোন উপায়ে পুনরুক্তিটি একটি সমকালীন মডেফিকেশন এক্সেক্সশন নিক্ষেপ করবে।

- রেফার করা জাভা ডক্স।


-1

আপনার কোড ম্যান চেক করুন ....

মূল পদ্ধতিতে আপনি চতুর্থ উপাদানটি সরানোর চেষ্টা করছেন যা সেখানে নেই এবং তাই ত্রুটি। অপসারণ পদ্ধতিতে আপনি তৃতীয় উপাদানটি অপসারণের চেষ্টা করছেন যা কোনও ত্রুটি নেই no


আপনি ভুল করেছেন: সংখ্যাগুলি 2এবং 3তালিকার সূচক নয়, তবে উপাদান। উভয় অপসারণ যুক্তি equalsতালিকা উপাদানগুলির বিরুদ্ধে পরীক্ষা করে, উপাদানগুলির সূচকটি নয়। তদ্ব্যতীত, যদি এটি সূচক সম্পর্কিত হয়, এটি হবে IndexOutOfBoundsException, না ConcurrentModificationException
মাল্টে হার্টভিগ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.