Vì sao lại bị ngoại lệ Exception in thread “main” java.util.ConcurrentModificationException?

Khi các bạn dùng đâu đó với collections trong java, ta cập nhật ở đây là thêm hoặc xóa các phần tử trong danh sách sẽ dẫn tới lỗi ConcurrentModificationException, vậy vì sao lại có lỗi trên và cách khắc phục như thế nào, chúng ta cùng tìm hiểu thông qua bài viết này.
Giả sử ta có một danh sách các số nguyên:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Ta muốn xóa đi 1 phần tử có giá trị là 1, vậy làm như sau:
Thường thì có 2 cách lặp, for và foreach :
Với for i:
for (int i = 0; i < l.size(); i++) {
if (i == 1) {
list.remove(1);
}
}
Với foreach:
for (Integer i : list) {
if (i == 1) {
list.remove(i);
}
}
Với trường hợp đầu tiên, chương trình chạy bình thường.
Với chương trình thứ 2 dùng foreach, chương trình sẽ bị lỗi ném ra 1 ngoại lệ:
Exception in thread “main” java.util.ConcurrentModificationException
Vậy câu hỏi là lý do vì sao với foreach lại bị lỗi trên, nhưng for i lại không lỗi?
Quay lại với trường hợp sử dụng foreach, khi ta lặp thì đang lặp các phần tử qua danh sách (ở đây là lặp chính list các object đang xử lý), ở đây là list chứa các phần tử, cho nên khi ta thay đổi (add/remove) các phần tử trong list, thì trường hợp này java không thể kiểm soát được chương trình với danh sách trên khi lặp foreach.
Hay nói cách khác thì khi dùng foreach thì các bạn không thể cập nhật các phần tử trong danh sách.
Với for i khi ta lặp thì ở đây chỉ lặp theo thứ tự các phần tử, vậy nên trường hợp này sẽ KHÔNG xảy ra lỗi. Tuy nhiên lưu ý khi sử dụng for i cập nhật lại các phần tử thì lưu ý tránh lỗi IndexOutOfBoundsException, bởi vì ta đang xóa nhưng lỡ không may get phần tử không nằm trong giới hạn của list thì sẽ bị lỗi trên.
Cách khắc phục ConcurrentModificationException?
Cách khắc phục một là các bạn có thể dụng for i như trên.
Cách tối ưu hơn thì các bạn dùng Iterator. Các bạn có thể tham khảo link bên dưới:
Iterator<Integer> i = l.iterator();
while (i.hasNext()) {
int item = (Integer) i.next();
if (item == 1) {
i.remove();
break;
}
}
Trong trường hợp nếu không dùng iterator và for i thì có nhiều cách giải quyết, chẳng hạn như:
List<Integer> list = new ArrayList<Integer>();
Collection<Integer> itemsToRemove = new ArrayList<Integer>();
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
for (Integer i : list) {
if (i.intValue() == 5)
itemsToRemove.add(i);
}
list.removeAll(itemsToRemove);
System.out.println(list);
Happy coding!

 

Các bài viết cùng chủ đề:

Top