অ্যারেলিস্ট থেকে উপাদানগুলি পুনরাবৃত্ত করার সময় এবং সরানোর সময় কীভাবে java.util.ConcurrentModificationsException এড়ানো যায়


203

আমার একটি অ্যারেলিস্ট রয়েছে যা আমি পুনরাবৃত্তি করতে চাই। এটির পুনরাবৃত্তি করার সময় আমাকে একই সাথে উপাদানগুলি সরিয়ে ফেলতে হবে। স্পষ্টতই এটি একটি ছুড়ে দেয় java.util.ConcurrentModificationException

এই সমস্যাটি পরিচালনা করার জন্য সেরা অনুশীলন কী? আমার আগে তালিকাটি ক্লোন করা উচিত?

আমি উপাদানগুলিকে লুপের মধ্যে না থেকে কোডের অন্য একটি অংশে সরিয়ে ফেলি।

আমার কোডটি এর মতো দেখাচ্ছে:

public class Test() {
    private ArrayList<A> abc = new ArrayList<A>();

    public void doStuff() {
        for (A a : abc) 
        a.doSomething();
    }

    public void removeA(A a) {
        abc.remove(a);
    }
}

a.doSomethingকল করতে পারে Test.removeA();


উত্তর:


325

দুটি বিকল্প:

  • আপনি মুছে ফেলতে চান এমন মানগুলির একটি তালিকা তৈরি করুন, লুপের মধ্যে সেই তালিকায় যুক্ত করুন , তারপরে originalList.removeAll(valuesToRemove)শেষে কল করুন
  • remove()পুনরাবৃত্তিতে নিজেই পদ্ধতিটি ব্যবহার করুন । মনে রাখবেন এর অর্থ আপনি লুপের জন্য বর্ধিত ব্যবহার করতে পারবেন না।

দ্বিতীয় বিকল্পের উদাহরণ হিসাবে, তালিকা থেকে 5 এর চেয়ে বেশি দৈর্ঘ্যের কোনও স্ট্রিং অপসারণ:

List<String> list = new ArrayList<String>();
...
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
    String value = iterator.next();
    if (value.length() > 5) {
        iterator.remove();
    }
}

2
আমার উল্লেখ করা উচিত ছিল যে আমি কোডের অন্য একটি অংশে উপাদানগুলি সরিয়েছি এবং লুপ নিজেই নয়।
RoflcoptrException

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

আমি জানি যে তালিকাটি ক্লোনিংয়ে সহায়তা করবে তবে আমি জানি না এটি একটি ভাল পদ্ধতির কিনা। তবে আমি আরও কিছু কোড যুক্ত করব।
RoflcoptrException

2
এই সমাধান এছাড়াও java.util.ConcurrentModificationException বাড়ে, দেখতে stackoverflow.com/a/18448699/2914140
কুলমাইন্ড

1
@ কুলমাইন্ড: একাধিক থ্রেড ব্যতীত এই কোডটি ভাল হওয়া উচিত।
জন স্কিটি

17

অ্যারেলিস্টের জাভাডোকস থেকে

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


6
এবং প্রশ্নের উত্তর কোথায়?
আদেলিন

যেমনটি
বরুণ আচার

14

আপনি উন্নত "লুপের জন্য" তালিকা থেকে মানটি সরিয়ে দেওয়ার চেষ্টা করছেন, যদি আপনি কোনও কৌশল প্রয়োগ করেন (তবে আপনি নিজের কোডটিতে যা করেছিলেন) তা সম্ভব নয়। এখানে অন্য পরামর্শ অনুসারে পুনরুক্তি স্তর কোড করা ভাল উপায়।

আমি অবাক হয়েছি কীভাবে লোকেরা লুপ পদ্ধতির জন্য সনাতন পরামর্শ দেয়নি।

for( int i = 0; i < lStringList.size(); i++ )
{
    String lValue = lStringList.get( i );
    if(lValue.equals("_Not_Required"))
    {
         lStringList.remove(lValue);
         i--; 
    }  
}

এটি পাশাপাশি কাজ করে।


2
এটা ঠিক নয় !!! আপনি যখন কোনও উপাদান অপসারণ করেন, পরবর্তীটি তার অবস্থান গ্রহণ করে এবং আমি যখন বৃদ্ধি করি তখন পরবর্তী উপাদানটি পরবর্তী পুনরাবৃত্তিতে পরীক্ষা করা হয় না। এই ক্ষেত্রে আপনার (int i = lStringList.size (); i> -1;
i--

1
একমত! বিকল্প হল সম্পাদন করা - লুপ জন্য যদি অবস্থার মধ্যে।
suhas0sn07

আমি মনে করি এই উত্তরটি উপরের মন্তব্যে সমস্যাগুলি সমাধান করার জন্য সম্পাদিত হয়েছিল, এটি এখন যেমনটি ঠিক তেমন কাজ করে তবে আমার পক্ষে।
কিরা রেসারি

11

আপনার সত্যই justতিহ্যবাহী উপায়ে অ্যারে ফিরে বারবার করা উচিত

প্রতিবার আপনি তালিকা থেকে কোনও উপাদান অপসারণ করবেন, এরপরের উপাদানগুলি এগিয়ে চলে যাবে। যতক্ষণ না আপনি পুনরাবৃত্তি হওয়া ব্যতীত অন্য উপাদানগুলি পরিবর্তন করবেন না, ততক্ষণ নিম্নলিখিত কোডটি কাজ করা উচিত।

public class Test(){
    private ArrayList<A> abc = new ArrayList<A>();

    public void doStuff(){
        for(int i = (abc.size() - 1); i >= 0; i--) 
            abc.get(i).doSomething();
    }

    public void removeA(A a){
        abc.remove(a);
    }
}

10

জাভা 8-তে আপনি সংগ্রহ ইন্টারফেসটি ব্যবহার করতে পারেন এবং অপসারণের পদ্ধতিটি কল করে এটি করতে পারেন:

yourList.removeIf((A a) -> a.value == 2);

আরও তথ্য এখানে পাওয়া যাবে


6

লুপটি স্বাভাবিক উপায়ে করুন, java.util.ConcurrentModificationExceptionঅ্যাক্সেস করা উপাদানগুলির সাথে সম্পর্কিত একটি ত্রুটি।

তাই চেষ্টা করুন:

for(int i = 0; i < list.size(); i++){
    lista.get(i).action();
}

আপনি java.util.ConcurrentModificationExceptionতালিকা থেকে কিছুই সরিয়ে না দিয়ে এড়িয়ে গেছেন। কৌশলী. :) আপনি কোনও তালিকা পুনরাবৃত্তি করতে সত্যই এটি "সাধারণ উপায়" বলতে পারবেন না।
জেডসোল্ট আকাশ

6

তালিকাটি পুনরাবৃত্তি করার সময়, আপনি যদি উপাদানটি সরাতে চান তবে এটি সম্ভব। আমার উদাহরণগুলির নীচে দেখুন,

ArrayList<String>  names = new ArrayList<String>();
        names.add("abc");
        names.add("def");
        names.add("ghi");
        names.add("xyz");

অ্যারে তালিকার উপরের নামগুলি আমার কাছে রয়েছে। এবং আমি উপরের তালিকা থেকে "ডিফ" নামটি মুছে ফেলতে চাই,

for(String name : names){
    if(name.equals("def")){
        names.remove("def");
    }
}

উপরের কোডটি কনক্রেন্টমোডিফিকেশন এক্সেপশন ব্যতিক্রম ছুঁড়েছে কারণ আপনি পুনরাবৃত্তি করার সময় তালিকাটি পরিবর্তন করছেন।

সুতরাং, এই পদ্ধতিতে অ্যারেলিস্ট থেকে "ডিফ" নামটি সরাতে,

Iterator<String> itr = names.iterator();            
while(itr.hasNext()){
    String name = itr.next();
    if(name.equals("def")){
        itr.remove();
    }
}

উপরের কোডটি, পুনরুক্তির মাধ্যমে আমরা অ্যারেলিস্ট থেকে "ডিফ" নামটি মুছে ফেলতে এবং অ্যারেটি প্রিন্ট করার চেষ্টা করতে পারি, আপনি নীচের আউটপুটটি দেখতে পাবেন।

আউটপুট: [এবিসি, জিআই, জাইজেড]


অন্যথায়, আমরা সমবর্তী তালিকায় ব্যবহার করতে পারি যা সমবর্তী প্যাকেজে পাওয়া যায়, যাতে আপনি পুনরাবৃত্তি করার সময় অপসারণ এবং অপারেশন যুক্ত করতে পারেন। উদাহরণস্বরূপ নীচের কোড স্নিপেট দেখুন। অ্যারেলিস্ট <স্ট্রিং> নামগুলি = নতুন অ্যারেলিস্ট <স্ট্রিং> (); কপিরআনওরাইটআরলিলিস্ট <স্ট্রিং> কপিরনমস = নতুন কপিরাইটনরাইটআরলিলিস্ট <স্ট্রিং> (নাম); (স্ট্রিং নাম: অনুলিপি নাম) - যদি (name.equals ("Def")) {copyNames.remove ("Def"); }}
ইন্দ্রা কে

কপিরআনওরাইটআরেলিস্ট ব্যয়বহুল ক্রিয়াকলাপ।
ইন্দ্র কে

5

একটি বিকল্প হ'ল removeAপদ্ধতিটি এটিকে সংশোধন করা -

public void removeA(A a,Iterator<A> iterator) {
     iterator.remove(a);
     }

কিন্তু তার মানে এই আপনার হবে doSomething()পাস করতে সক্ষম হওয়া উচিত iteratorকরতে removeপদ্ধতি। খুব ভাল ধারণা নয়।

আপনি এটি দুটি পদক্ষেপের পদ্ধতিতে করতে পারেন: আপনি যখন তালিকাটির উপরে পুনরাবৃত্তি করবেন তখন প্রথম লুপে, নির্বাচিত উপাদানগুলি সরিয়ে না দেওয়ার পরিবর্তে, মুছে ফেলা হিসাবে চিহ্নিত করুন । এর জন্য, আপনি কেবল এই উপাদানগুলি (অগভীর অনুলিপি) অন্য কোনও অনুলিপি করতে পারেন ।List

তারপরে, আপনার পুনরাবৃত্তিটি সম্পন্ন হয়ে গেলে, removeAllদ্বিতীয় তালিকার সমস্ত উপাদান প্রথম তালিকা থেকে কেবল একটি করুন ।


দুর্দান্ত, আমি একই পদ্ধতি ব্যবহার করেছি, যদিও আমি দু'বার লুপ করেছি op এটি বিষয়গুলিকে সহজ করে তোলে এবং এতে কোনও সমকালীন সমস্যা নেই :)
পঙ্কজ নিমগাদ

1
আমি দেখতে পাচ্ছি না যে আইট্রেটারের একটি অপসারণ পদ্ধতি (ক) আছে। অপসারণ () কোনও ডকুমেন্টস.ওরকল / জাভ্যাস / / / ডকস / এপি / জাভা / ইউটিল / আইট্রেটার এইচটিএমএল নিচ্ছে না আমি কী অনুপস্থিত?
c0der

5

এখানে একটি উদাহরণ যেখানে আমি অপসারণের জন্য বস্তুগুলি যুক্ত করতে একটি পৃথক তালিকা ব্যবহার করি, তারপরে আমি মূল তালিকা থেকে উপাদানগুলি সরিয়ে ফেলার জন্য স্ট্রিম.ফরঞ্চ ব্যবহার করি:

private ObservableList<CustomerTableEntry> customersTableViewItems = FXCollections.observableArrayList();
...
private void removeOutdatedRowsElementsFromCustomerView()
{
    ObjectProperty<TimeStamp> currentTimestamp = new SimpleObjectProperty<>(TimeStamp.getCurrentTime());
    long diff;
    long diffSeconds;
    List<Object> objectsToRemove = new ArrayList<>();
    for(CustomerTableEntry item: customersTableViewItems) {
        diff = currentTimestamp.getValue().getTime() - item.timestamp.getValue().getTime();
        diffSeconds = diff / 1000 % 60;
        if(diffSeconds > 10) {
            // Element has been idle for too long, meaning no communication, hence remove it
            System.out.printf("- Idle element [%s] - will be removed\n", item.getUserName());
            objectsToRemove.add(item);
        }
    }
    objectsToRemove.stream().forEach(o -> customersTableViewItems.remove(o));
}

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

আমি মনে করি না আপনি প্রথম লুপের মধ্যে থেকে অবজেক্টটি সরিয়ে ফেলতে পারবেন, অতএব অতিরিক্ত অপসারণের লুপের প্রয়োজন, অপসারণের লুপটি কেবল অপসারণের জন্য অবজেক্টস - সম্ভবত আপনি কেবল একটি লুপ দিয়ে উদাহরণ লিখতে পারেন, আমি এটি দেখতে চাই - ধন্যবাদ @ লুইস কার্লোস
সেরাপ

আপনি এই কোডটি দিয়ে বলছেন আপনি ফোর-লুপের অভ্যন্তরে কোনও উপাদান সরাতে পারবেন না কারণ এটি java.util.ConcurrentModificationsException ব্যতিক্রম ঘটায়। তবে আপনি এর জন্য একটি বেসিক ব্যবহার করতে পারেন। এখানে আমি আপনার কোডের অংশটি ব্যবহার করে একটি উদাহরণ লিখছি।
লুইস কার্লোস

1
(int i = 0; i <গ্রাহকদের টেবিলভিউআইটেমস.সাইজ (); i++) f ডিফফ = কারেন্টটাইমস্ট্যাম্প.জেটভ্যালু () ডিফসেকেন্ডস = ডিফ / 1000% 60; যদি (ডিফেস সেকেন্ডস> 10) {গ্রাহক টেবিলভিউ আইটেমস.রেমোভ (i--); } Important গুরুত্বপূর্ণ আমি - কারণ আপনি কোনও এলিমেন্ট এড়িয়ে যেতে চান না। এছাড়াও আপনি অ্যারেলিস্ট ক্লাস দ্বারা সরবরাহিত পদ্ধতিটি মুছে ফেলুন (প্রিডিকেট <? সুপার ই> ফিল্টার) ব্যবহার করতে পারেন। আশা করি এই সহায়তা
লুইস কার্লোস

1
ব্যতিক্রম ঘটে কারণ তালিকার পুনরাবৃত্তির সক্রিয় রেফারেন্স হিসাবে সেখানে লুপে in সাধারণ ক্ষেত্রে, এখানে কোনও রেফারেন্স নেই এবং ডেটা পরিবর্তন করার জন্য আপনার আরও নমনীয়তা রয়েছে। আশা করি এই সহায়তা
লুইস কার্লোস

3

প্রতিটি লুপের জন্য ব্যবহার না করে লুপের জন্য স্বাভাবিক ব্যবহার করুন। উদাহরণস্বরূপ, নীচের কোডটি java.util.ConcurrentModificationsException না দিয়ে অ্যারে তালিকার সমস্ত উপাদান সরিয়ে দেয়। আপনি আপনার ব্যবহারের কেস অনুসারে লুপের শর্তটি পরিবর্তন করতে পারেন।

   for(int i=0;i<abc.size();i++)  {

          e.remove(i);
        }

2

এভাবে কিছু সহজ করুন:

for (Object object: (ArrayList<String>) list.clone()) {
    list.remove(object);
}

2

স্ট্রিম ব্যবহার করে একটি বিকল্প জাভা 8 সমাধান:

        theList = theList.stream()
            .filter(element -> !shouldBeRemoved(element))
            .collect(Collectors.toList());

জাভা 7 এ পরিবর্তে আপনি পেয়ারা ব্যবহার করতে পারেন:

        theList = FluentIterable.from(theList)
            .filter(new Predicate<String>() {
                @Override
                public boolean apply(String element) {
                    return !shouldBeRemoved(element);
                }
            })
            .toImmutableList();

দ্রষ্টব্য, যে পেয়ারা উদাহরণের ফলে একটি পরিবর্তনযোগ্য তালিকার ফলস্বরূপ যা আপনি চান তা হতে পারে বা নাও পারে।


1

আপনি একটি অ্যারেলিস্টের পরিবর্তে কপিরাইটঅনরাইটআরলিলিস্টও ব্যবহার করতে পারেন। এটি জেডিকে ২.৫ এর পর থেকে সর্বশেষ প্রস্তাবিত পদ্ধতির।


1

আমার ক্ষেত্রে, গৃহীত উত্তরটি কাজ করছে না, এটি ব্যতিক্রম বন্ধ করে দেয় তবে এটি আমার তালিকায় কিছুটা অসঙ্গতি সৃষ্টি করে। নিম্নলিখিত সমাধানটি আমার পক্ষে নিখুঁতভাবে কাজ করছে।

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

for (String value: list) {
   if (value.length() > 5) { // your condition
       itemsToRemove.add(value);
   }
}
list.removeAll(itemsToRemove);

এই কোডটিতে আমি অন্য তালিকায় আইটেমগুলি অপসারণ করতে যুক্ত করেছি এবং তারপরে list.removeAllসমস্ত প্রয়োজনীয় আইটেমগুলি সরিয়ে ফেলার পদ্ধতিটি ব্যবহার করেছি ।


0

"আমি কি প্রথমে তালিকাটি ক্লোন করব?"

এটি সবচেয়ে সহজ সমাধান হবে, ক্লোন থেকে অপসারণ করুন এবং অপসারণের পরে ক্লোনটি আবার অনুলিপি করুন।

আমার রুমিকুব গেমের একটি উদাহরণ:

SuppressWarnings("unchecked")
public void removeStones() {
  ArrayList<Stone> clone = (ArrayList<Stone>) stones.clone();
  // remove the stones moved to the table
  for (Stone stone : stones) {
      if (stone.isOnTable()) {
         clone.remove(stone);
      }
  }
  stones = (ArrayList<Stone>) clone.clone();
  sortStones();
}

2
ডাউনভোটারদের ডাউনভোটিংয়ের আগে কমপক্ষে একটি মন্তব্য করা উচিত।
ওয়ানওয়ার্ল্ড

2
এই উত্তরের সাথে অন্তর্নিহিত কোনও ভুল নেই আশা করা যায় stones = (...) clone.clone();এটি অতিমাত্রায়। stones = clone;একই কাজ করবেন না ?
ভাইকিংস্টিভ

আমি একমত, দ্বিতীয় ক্লোনিং অপ্রয়োজনীয়। আপনি ক্লোনটিতে পুনরাবৃত্তি করে এটিকে আরও সহজ করতে পারেন এবং উপাদানগুলি সরাসরি থেকে সরিয়ে ফেলতে পারেন stones। এইভাবে আপনার cloneভেরিয়েবলটিরও প্রয়োজন নেই : for (Stone stone : (ArrayList<Stone>) stones.clone()) {...
Zsolt স্কাই

0

যদি আপনার লক্ষ্যটি তালিকা থেকে সমস্ত উপাদান সরিয়ে ফেলা হয় তবে আপনি প্রতিটি আইটেমটি নিয়ে পুনরাবৃত্তি করতে পারেন এবং তারপরে কল করতে পারেন:

list.clear()

0

আমি দেরিতে পৌঁছেছি জানি তবে আমি এইটির উত্তর দিচ্ছি কারণ আমি মনে করি এই সমাধানটি সহজ এবং মার্জিত:

List<String> listFixed = new ArrayList<String>();
List<String> dynamicList = new ArrayList<String>();

public void fillingList() {
    listFixed.add("Andrea");
    listFixed.add("Susana");
    listFixed.add("Oscar");
    listFixed.add("Valeria");
    listFixed.add("Kathy");
    listFixed.add("Laura");
    listFixed.add("Ana");
    listFixed.add("Becker");
    listFixed.add("Abraham");
    dynamicList.addAll(listFixed);
}

public void updatingListFixed() {
    for (String newList : dynamicList) {
        if (!listFixed.contains(newList)) {
            listFixed.add(newList);
        }
    }

    //this is for add elements if you want eraser also 

    String removeRegister="";
    for (String fixedList : listFixed) {
        if (!dynamicList.contains(fixedList)) {
            removeResgister = fixedList;
        }
    }
    fixedList.remove(removeRegister);
}

এগুলি সমস্তই একটি তালিকা থেকে অন্য তালিকায় আপডেট করার জন্য এবং আপনি কেবলমাত্র একটি তালিকা থেকে সমস্ত পদ্ধতি তৈরি করতে পারেন এবং পদ্ধতি আপডেটে আপনি উভয় তালিকা পরীক্ষা করে দেখতে পারেন এবং উপাদানগুলি বিটওয়েন তালিকায় মুছতে বা যুক্ত করতে পারেন। এর অর্থ উভয় তালিকার সর্বদা এটি একই আকার


0

অ্যারে তালিকার পরিবর্তে Iterator ব্যবহার করুন

টাইপ ম্যাচের সাথে একটি সেটকে পুনরায় আবরণে রূপান্তর করতে হবে

এবং পরবর্তী উপাদান এ সরান এবং সরান

Iterator<Insured> itr = insuredSet.iterator();
while (itr.hasNext()) { 
    itr.next();
    itr.remove();
}

পরবর্তীগুলিতে স্থানান্তর করা এখানে গুরুত্বপূর্ণ কারণ এটি উপাদানটি সরিয়ে ফেলার জন্য সূচিটি নেওয়া উচিত।


0

কি সম্পর্কে

import java.util.Collections;

List<A> abc = Collections.synchronizedList(new ArrayList<>());

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.