2011-11-18 62 views
5

Tôi gặp sự cố khi xóa các phần tử của danh sách trong khi lặp qua danh sách. Mã số:Tự động xóa các phần tử khỏi Danh sách

For (WebElement element: list){ 
    if (!element.isEnabled() || !element.isSelected()){ 
     list.remove(element); 
    } 
} 

Tôi nhận được ConcurrentModificationException, mà tôi hoàn toàn hiểu. Tôi đang xóa một mục khỏi danh sách trong khi trong vòng lặp đi qua danh sách. Trực giác, điều đó sẽ làm hỏng việc lập chỉ mục của vòng lặp.

Câu hỏi của tôi là, cách khác, tôi nên xóa các phần tử không phải là enabled hoặc selected khỏi danh sách này?

Trả lời

8

Cách đơn giản nhất để loại bỏ các yếu tố từ một danh sách trong một vòng lặp là sử dụng một ListIterator và loại bỏ các yếu tố sử dụng thường xuyên iterator.remove()

+0

Tôi không biết liệu nó có nhất thiết phải dễ nhất hay không. 'remove()' là một phần chức năng tùy chọn trên giao diện 'Iterator '. Cũng cần lưu ý rằng 'remove()' nằm trên 'Iterator ' và chỉ được thừa kế bởi 'ListIterator '. – corsiKa

6

Sửa đổi một danh sách trong khi iterating qua nó, theo một cách bên ngoài của việc sử dụng lặp, kết quả trong hành vi không xác định. Bạn sẽ phải sử dụng một trình lặp một cách rõ ràng:

Iterator<WebElement> iter = list.iterator(); 
while (iter.hasNext()) { 
    WebElement element = iter.next(); 
    if (!element.isEnabled() || !element.isSelected()) { 
     iter.remove(); 
    } 
} 

Xem this question để biết thêm.

+0

Hmm Tôi hiểu. Vì vậy, nếu tôi muốn chuyển đổi 'Iterator' trở lại một' Danh sách', có cách nào dễ dàng hơn là chỉ thêm từng phần tử một trong một vòng lặp không? – jamesfzhang

+2

Điều này không chuyển đổi 'List' thành' Iterator' - một 'Iterator' chỉ là một đối tượng hoạt động trên chính danh sách đó - đó là một giao diện để lặp qua danh sách. Khi bạn gọi 'iter.remove()', nó thực sự đang sửa đổi danh sách bên dưới. – Claudiu

+0

Wow, thật tuyệt vời! Cảm ơn. – jamesfzhang

0

Kết quả ConcurrentModificationException thực tế là cú pháp cho mỗi cú pháp chỉ là đường cú pháp để sử dụng giao diện Iterator.

Danh sách trình vòng lặp có thuộc tính "không nhanh", có nghĩa là bất kỳ thay đổi nào được thực hiện cho danh sách ngoài giao diện do trình vòng lặp cung cấp, ngay lập tức vô hiệu hóa trình lặp nói trên. Việc cố gắng sử dụng trình vòng lặp không hợp lệ sẽ kích hoạt ngoại lệ của bạn.

@Claudiu đã đăng mã này, nhưng để rõ ràng, tôi cũng sẽ đặt nó ở đây. Để làm những gì bạn đang cố gắng làm, bạn sẽ phải thả cú pháp ưa thích và sử dụng một Iterator trần.

Iterator<WebElement iter = list.iterator(); 
while (iter.hasNext()) { 
    WebElement element = iter.next(); 
    if (!element.isEnabled() || !element.isSelected()) { 
     iter.remove(); 
    } 
} 
3

Những người khác đã đề xuất sử dụng trình lặp danh sách. Điều đó đã chứng tỏ hữu ích cho tôi, nhưng tiếc là nó dựa trên một phương pháp, remove(), được coi là tùy chọn bởi giao diện Iterable<E>.

Quoth Javadoc, nevermore (tôi nhấn mạnh):

trống remove()

Xóa khỏi bộ sưu tập cơ bản các yếu tố cuối cùng được trả về bởi iterator (hoạt động không bắt buộc).

Để khắc phục điều đó đã chứng minh hữu ích hơn đối với tôi là danh sách xóa.

List<E> removed = new ArrayList<E>(); 
for(E element : list) { 
    if(someCondition) removed.add(element); 
} 
list.removeAll(removed); 

Điều này mang lại cho bạn một lịch sử về những gì bạn đã xóa, giống như phương pháp xóa.

+0

Tôi thích cái này rất nhiều (+1). Tuy nhiên, phần tử E phải có một ghi đè thích hợp của phương thức equals – GETah

+1

@GETah không nhất thiết. Nó sẽ làm việc tốt mà không có nó, và thậm chí có thể được ưa thích. Bạn có thể có chúng đến từ một phương pháp nhà máy, trong đó bạn có ít hơn nhiều nhu cầu về phương pháp equals, dựa hoàn toàn vào tham chiếu cho bình đẳng. – corsiKa

+1

Chà tôi cũng thích điều này rất nhiều! Rất tốt bên ngoài hộp suy nghĩ. – jamesfzhang

Các vấn đề liên quan