Lặp lại thông qua Bộ sưu tập, tránh ConcurrencyModificationException khi xóa các đối tượng trong một vòng lặp


1194

Chúng tôi đều biết bạn không thể làm như sau vì ConcurrentModificationException:

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

Nhưng điều này rõ ràng đôi khi hoạt động, nhưng không phải luôn luôn. Đây là một số mã cụ thể:

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);
}

Điều này, tất nhiên, kết quả trong:

Exception in thread "main" java.util.ConcurrentModificationException

Mặc dù nhiều chủ đề không làm điều đó. Dù sao.

Giải pháp tốt nhất cho vấn đề này là gì? Làm thế nào tôi có thể xóa một mục khỏi bộ sưu tập trong một vòng lặp mà không ném ngoại lệ này?

Tôi cũng đang sử dụng một tùy ý Collectionở đây, không nhất thiết là một ArrayList, vì vậy bạn không thể dựa vào get.


Lưu ý cho độc giả: hãy đọc docs.oracle.com/javase/tutorial/collections/interfaces/ , nó có thể có một cách dễ dàng hơn để đạt được những gì bạn muốn làm.
GKFX

Câu trả lời:


1601

Iterator.remove() là an toàn, bạn có thể sử dụng nó như thế này:

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();
    }
}

Lưu ý rằng đó Iterator.remove()là cách an toàn duy nhất để sửa đổi bộ sưu tập trong quá trình lặp; hành vi không được chỉ định nếu bộ sưu tập cơ bản được sửa đổi theo bất kỳ cách nào khác trong khi quá trình lặp đang diễn ra.

Nguồn: docs.oracle> Giao diện bộ sưu tập


Và tương tự, nếu bạn có ListIteratorvà muốn thêm các mục, bạn có thể sử dụng ListIterator#add, với cùng lý do bạn có thể sử dụng Iterator#remove - nó được thiết kế để cho phép nó.


Trong trường hợp của bạn, bạn đã cố gắng để loại bỏ khỏi danh sách, nhưng những hạn chế cũng áp dụng nếu cố gắng để putthành một Maptrong khi lặp lại nội dung của nó.


19
Điều gì xảy ra nếu bạn muốn loại bỏ một phần tử khác với phần tử được trả về trong lần lặp hiện tại?
Eugen

2
Bạn phải sử dụng .remove trong iterator và điều đó chỉ có thể xóa phần tử hiện tại, vì vậy không :)
Bill K

1
Xin lưu ý rằng việc này chậm hơn so với việc sử dụng ConcurrencyLinkedDeque hoặc CopyOnWriteArrayList (ít nhất là trong trường hợp của tôi)
Dan

1
Có phải là không thể thực hiện iterator.next()cuộc gọi trong vòng lặp for? Nếu không, ai đó có thể giải thích tại sao?
Blake

1
@GonenI Nó được triển khai cho tất cả các trình vòng lặp từ các bộ sưu tập không phải là bất biến. List.addcũng là "tùy chọn" theo nghĩa tương tự, nhưng bạn sẽ không nói nó "không an toàn" để thêm vào danh sách.
Radiodef

345

Những công việc này:

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

Tôi giả định rằng vì một vòng lặp foreach là cú pháp cú pháp để lặp lại, sử dụng một trình vòng lặp sẽ không giúp ích gì ... nhưng nó mang lại cho bạn .remove()chức năng này .


43
vòng lặp foreach cú pháp đường để lặp. Tuy nhiên, như bạn đã chỉ ra, bạn cần gọi remove trên iterator - điều mà foreach không cho phép bạn truy cập. Do đó, lý do tại sao bạn không thể xóa trong vòng lặp foreach (mặc dù bạn thực sự đang sử dụng một trình vòng lặp dưới mui xe)
madlep

36
+1 ví dụ mã để sử dụng iter.remove () trong ngữ cảnh mà câu trả lời của Bill K không [trực tiếp] có.
Được chỉnh sửa

202

Với Java 8, bạn có thể sử dụng phương thức mớiremoveIf . Áp dụng cho ví dụ của bạn:

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

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

3
Ôi trời! Tôi đã hy vọng một cái gì đó trong Java 8 hoặc 9 có thể giúp đỡ. Điều này vẫn có vẻ khá dài dòng đối với tôi, nhưng tôi vẫn thích nó.
James T Snell

Là thực hiện bằng () được đề nghị trong trường hợp này quá?
Anmol Gupta

bằng cách removeIfsử dụng Iteratorwhilevòng lặp. Bạn có thể thấy nó tại java 8java.util.Collection.java
omerhakanbilici

3
@omerhakanbilici Một số triển khai như ArrayListghi đè lên vì lý do hiệu suất. Một trong những bạn đang đề cập đến chỉ là thực hiện mặc định.
Didier L

@AnmolGupta: Không, hoàn toàn equalskhông được sử dụng ở đây, vì vậy nó không phải thực hiện. (Nhưng tất nhiên, nếu bạn sử dụng equalstrong bài kiểm tra của mình thì nó phải được thực hiện theo cách bạn muốn.)
Lii

42

Vì câu hỏi đã được trả lời, cách tốt nhất là sử dụng phương thức remove của đối tượng iterator, tôi sẽ đi vào chi tiết cụ thể về nơi "java.util.ConcurrentModificationException"ném lỗi .

Mỗi lớp bộ sưu tập có một lớp riêng thực hiện giao diện Iterator và cung cấp các phương thức như next(), remove()hasNext().

Mã cho tiếp theo trông giống như thế này ...

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

Ở đây phương thức checkForComodificationđược thực hiện như

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

Vì vậy, như bạn có thể thấy, nếu bạn rõ ràng cố gắng loại bỏ một yếu tố khỏi bộ sưu tập. Nó dẫn đến modCountviệc nhận được khác nhau expectedModCount, dẫn đến ngoại lệ ConcurrentModificationException.


Rất thú vị. Cảm ơn bạn! Bản thân tôi thường không gọi remove (), thay vào đó tôi thích xóa bộ sưu tập sau khi lặp qua nó. Không phải nói rằng đó là một mô hình tốt, chỉ là những gì tôi đã làm gần đây.
James T Snell

26

Bạn có thể sử dụng iterator trực tiếp như bạn đã đề cập hoặc nếu không thì giữ một bộ sưu tập thứ hai và thêm từng mục bạn muốn xóa vào bộ sưu tập mới, sau đó xóa ALL ở cuối. Điều này cho phép bạn tiếp tục sử dụng loại an toàn của vòng lặp cho mỗi vòng với chi phí sử dụng bộ nhớ và thời gian cpu tăng (không phải là một vấn đề lớn trừ khi bạn có danh sách thực sự lớn hoặc thực sự cũ)

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
đây là những gì tôi thường làm, nhưng trình lặp rõ ràng là một giải pháp tuyệt vời hơn tôi cảm thấy.
Claudiu

1
Đủ công bằng, miễn là bạn không làm gì khác với iterator - việc tiếp xúc với nó sẽ giúp thực hiện những việc như gọi .next () hai lần trên mỗi vòng lặp, v.v. Không phải là vấn đề lớn, nhưng có thể gây ra sự cố nếu bạn đang làm bất cứ điều gì phức tạp hơn là chỉ chạy qua một danh sách để xóa các mục.
RodeoClown

@RodeoClown: trong câu hỏi ban đầu, Claudiu đang xóa khỏi Bộ sưu tập, không phải là trình vòng lặp.
matt b

1
Xóa khỏi iterator sẽ xóa khỏi bộ sưu tập cơ bản ... nhưng điều tôi đã nói trong bình luận cuối cùng là nếu bạn đang làm bất cứ điều gì phức tạp hơn là chỉ tìm kiếm xóa trong vòng lặp (như xử lý dữ liệu chính xác) bằng cách sử dụng iterator có thể tạo ra một số lỗi dễ thực hiện hơn.
RodeoClown

Nếu đó là một giá trị xóa đơn giản không cần thiết và vòng lặp chỉ thực hiện một điều đó, sử dụng trình lặp trực tiếp và gọi .remove () là hoàn toàn tốt.
RodeoClown

17

Trong những trường hợp như vậy, một mẹo phổ biến là (đã?) Để đi ngược lại:

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

Điều đó nói rằng, tôi rất vui khi bạn có các cách tốt hơn trong Java 8, ví dụ removeIfhoặc filtertrên các luồng.


2
Đây là một mẹo hay. Nhưng nó sẽ không hoạt động trên các bộ sưu tập không được lập chỉ mục như các bộ và nó sẽ rất chậm đối với các danh sách được liên kết.
Claudiu

@Claudiu Vâng, điều này chắc chắn chỉ dành cho ArrayLists hoặc các bộ sưu tập tương tự.
Landei

Tôi đang sử dụng một ArrayList, điều này hoạt động hoàn hảo, cảm ơn.
StarSweeper

2
chỉ số là tuyệt vời. Nếu nó quá phổ biến tại sao bạn không sử dụng for(int i = l.size(); i-->0;) {?
John

16

Câu trả lời tương tự như Claudius với một vòng lặp for:

for (Iterator<Object> it = objects.iterator(); it.hasNext();) {
    Object object = it.next();
    if (test) {
        it.remove();
    }
}

12

Với Bộ sưu tập Eclipse , phương thức removeIfđược định nghĩa trên MutableCollection sẽ hoạt động:

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);

Với cú pháp Lambda Java 8, điều này có thể được viết như sau:

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);

Cuộc gọi đến Predicates.cast()là cần thiết ở đây vì một removeIfphương thức mặc định đã được thêm vào java.util.Collectiongiao diện trong Java 8.

Lưu ý: Tôi là người đi làm cho Bộ sưu tập Eclipse .


10

Tạo một bản sao của danh sách hiện có và lặp lại trên bản sao mới.

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

19
Tạo một bản sao nghe có vẻ lãng phí tài nguyên.
Antzi

3
@Antzi Điều đó phụ thuộc vào kích thước của danh sách và mật độ của các đối tượng bên trong. Vẫn là một giải pháp có giá trị và hợp lệ.
MRE

Tôi đã và đang sử dụng phương pháp này. Nó cần một chút tài nguyên, nhưng linh hoạt và rõ ràng hơn nhiều.
Tao Zhang

Đây là một giải pháp tốt khi bạn không có ý định loại bỏ các đối tượng bên trong vòng lặp, nhưng chúng được loại bỏ "ngẫu nhiên" khỏi các luồng khác (ví dụ: hoạt động mạng cập nhật dữ liệu). Nếu bạn thấy mình làm những bản sao rất nhiều thậm chí còn có một thi java làm chính xác này: docs.oracle.com/javase/8/docs/api/java/util/concurrent/...
A1m

8

Mọi người đang khẳng định người ta không thể xóa khỏi Bộ sưu tập được lặp lại bởi một vòng lặp foreach. Tôi chỉ muốn chỉ ra rằng về mặt kỹ thuật không chính xác và mô tả chính xác (tôi biết câu hỏi của OP rất tiên tiến để tránh sự hiểu biết này) mã đằng sau giả định đó:

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
    }
}

Không phải là bạn không thể xóa khỏi vòng lặp Colletionmà thay vào đó bạn không thể tiếp tục lặp lại sau khi thực hiện. Do đó breaktrong mã ở trên.

Xin lỗi nếu câu trả lời này là trường hợp sử dụng hơi chuyên gia và phù hợp hơn với chủ đề ban đầu tôi đến từ đây, câu hỏi đó được đánh dấu là trùng lặp (mặc dù chủ đề này xuất hiện nhiều sắc thái hơn) và bị khóa.


8

Với vòng lặp truyền thống

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++;   
}

Ah, vậy nó thực sự chỉ là vòng lặp nâng cao ném ngoại lệ.
cellepo

FWIW - cùng một mã sẽ vẫn hoạt động sau khi được sửa đổi thành tăng i++trong bộ bảo vệ vòng lặp chứ không phải trong thân vòng lặp.
cellepo

Sửa chữa ^: Đó là nếu i++gia tăng không có điều kiện - Tôi thấy bây giờ đó là lý do tại sao bạn làm điều đó trong cơ thể :)
cellepo

2

A ListIteratorcho phép bạn thêm hoặc xóa các mục trong danh sách. Giả sử bạn có một danh sách các Carđối tượng:

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);
   }
}

Các phương thức bổ sung trong giao diện ListIterator (phần mở rộng của Iterator) rất thú vị - đặc biệt là previousphương thức của nó .
cellepo

1

Tôi có một đề nghị cho vấn đề trên. Không cần danh sách thứ cấp hoặc bất kỳ thời gian thêm. Vui lòng tìm một ví dụ sẽ làm những việc tương tự nhưng theo một cách khác.

//"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;
}

Điều này sẽ tránh Ngoại lệ đồng thời.


1
Câu hỏi nêu rõ, OP không cần thiết sử dụng ArrayListvà do đó không thể dựa vào get(). Nếu không, có lẽ là một cách tiếp cận tốt, mặc dù.
kaskelotti

(Làm rõ ^) OP đang sử dụng một giao diện tùy ý Collection- Collectionkhông bao gồm get. (Mặc dù Listgiao diện FWIW không bao gồm 'get').
cellepo

Tôi vừa thêm một câu trả lời riêng, chi tiết hơn ở đây cũng cho while-looping a List. Nhưng +1 cho câu trả lời này vì nó xuất hiện đầu tiên.
cellepo

1

ConcảnHashMap hoặc ConcurrencyLinkedQueue hoặc ConcảnSkipListMap có thể là một tùy chọn khác, bởi vì họ sẽ không bao giờ ném bất kỳ ConcurrencyModificationException nào, ngay cả khi bạn xóa hoặc thêm mục.


Đúng, và lưu ý rằng tất cả đều trong java.util.concurrentgói. Một số lớp tương tự / trường hợp sử dụng chung khác từ gói đó là CopyOnWriteArrayList & CopyOnWriteArraySet [nhưng không giới hạn ở các lớp đó].
cellepo

Trên thực tế, tôi mới biết rằng mặc dù các đối tượng cấu trúc dữ liệu đó tránh ConcurrentModificationException , sử dụng chúng trong vòng lặp nâng cao vẫn có thể gây ra sự cố lập chỉ mục (ví dụ: vẫn bỏ qua các phần tử hoặc IndexOutOfBoundsException...)
cellepo

1

Tôi biết câu hỏi này quá cũ so với Java 8, nhưng đối với những người sử dụng Java 8, bạn có thể dễ dàng sử dụng remove If ():

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

Một cách khác là tạo một bản sao của ArrayList của bạn:

List<Object> l = ...

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

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

Lưu ý: ikhông phải là một indexmà thay vào đó là đối tượng. Có lẽ gọi nó objsẽ phù hợp hơn.
luckydonald

1

Cách tốt nhất (Được khuyến nghị) là sử dụng gói java.util.Conc hiện. Bằng cách sử dụng gói này, bạn có thể dễ dàng tránh Ngoại lệ này. tham khảo mã sửa đổi

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

Trong trường hợp ArrayList: remove (int index) - if (index là vị trí của phần tử cuối cùng), nó sẽ tránh System.arraycopy()và không mất thời gian cho việc này.

thời gian mảng tăng nếu (chỉ số giảm), bằng cách các yếu tố của danh sách cũng giảm!

cách loại bỏ hiệu quả tốt nhất là- loại bỏ các phần tử của nó theo thứ tự giảm dần: while(list.size()>0)list.remove(list.size()-1);// takes O (1) while(list.size()>0)list.remove(0);// takes O (factorial (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
  • cho vòng lặp chỉ mục: 1090 msec
  • cho chỉ số desc: 519 msec --- tốt nhất
  • cho vòng lặp: 1043 ms

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

Bắt là sau khi loại bỏ phần tử khỏi danh sách nếu bạn bỏ qua lệnh gọi iterator.next () nội bộ. nó vẫn làm việc! Mặc dù tôi không đề xuất viết mã như thế này nhưng nó giúp hiểu được khái niệm đằng sau nó :-)

Chúc mừng!


0

Ví dụ về sửa đổi bộ sưu tập an toàn chủ đề:

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

Tôi biết câu hỏi này giả sử chỉ là một Collection, và không cụ thể hơn bất kỳ List. Nhưng đối với những người đọc câu hỏi này thực sự đang làm việc với một Listtài liệu tham khảo, bạn có thể tránh ConcurrentModificationExceptionbằng một while-loop (trong khi sửa đổi bên trong nó) thay vào đó nếu bạn muốn tránhIterator (hoặc nếu bạn muốn tránh nó nói chung, hoặc tránh nó một cách cụ thể để đạt được một thứ tự lặp khác với dừng từ đầu đến cuối ở mỗi phần tử [mà tôi tin là thứ tự duy nhất Iteratorcó thể làm]):

* Cập nhật: Xem các bình luận bên dưới để làm rõ sự tương tự cũng có thể đạt được với vòng lặp truyền thống .

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;
    }
}

Không có đồng thờiExceptionException từ mã đó.

Ở đó chúng ta thấy việc lặp không bắt đầu ngay từ đầu và không dừng lại ở mọi yếu tố (mà tôi tinIterator bản thân nó không thể làm được).

FWIW chúng ta cũng thấy getđược gọi list, điều này không thể thực hiện được nếu tham chiếu của nó chỉ là Collection(thay vì Listkiểu cụ thể hơn Collection) - Listgiao diện bao gồm get, nhưng Collectiongiao diện thì không. Nếu không phải vì sự khác biệt đó, thì listtham chiếu có thể thay vào đó là Collection[và do đó về mặt kỹ thuật, Câu trả lời này sẽ là Câu trả lời trực tiếp, thay vì Câu trả lời tiếp tuyến].

FWIWW cùng mã vẫn hoạt động sau khi được sửa đổi để bắt đầu tại điểm dừng tại mọi phần tử (giống như Iteratorthứ tự):

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;
    }
}

Điều này vẫn đòi hỏi tính toán rất cẩn thận của các chỉ dẫn để loại bỏ, tuy nhiên.
OneCricketeer

Ngoài ra, đây chỉ là một lời giải thích chi tiết hơn về câu trả lời này stackoverflow.com/a/43441822/2308683
OneCricketeer

Điều tốt để biết - cảm ơn! Câu trả lời khác đó giúp tôi hiểu rằng đó là vòng lặp nâng cao sẽ ném ConcurrentModificationException, nhưng không phải là vòng lặp truyền thống (mà Câu trả lời khác sử dụng) - không nhận ra rằng trước đây là lý do tại sao tôi có động lực viết Câu trả lời này (tôi đã nhầm sau đó nghĩ rằng tất cả các vòng lặp sẽ ném Ngoại lệ).
cellepo

0

Một giải pháp có thể là xoay danh sách và loại bỏ phần tử đầu tiên để tránh ConcurrencyModificationException hoặc IndexOutOfBoundException

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

Hãy thử cái này (loại bỏ tất cả các thành phần trong danh sách bằng nhau i):

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

0

bạn cũng có thể sử dụng đệ quy

Đệ quy trong java là một quá trình trong đó một phương thức gọi chính nó liên tục. Một phương thức trong java tự gọi nó được gọi là phương thức đệ quy.


-2

đây có thể không phải là cách tốt nhất, nhưng đối với hầu hết các trường hợp nhỏ thì điều này có thể chấp nhận được:

"tạo một mảng trống thứ hai và chỉ thêm những mảng bạn muốn giữ"

Tôi không nhớ nơi tôi đã đọc nó từ ... vì sự công bằng tôi sẽ tạo wiki này với hy vọng ai đó tìm thấy nó hoặc chỉ để không kiếm được đại diện mà tôi không xứng đáng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.