2013-05-19 55 views
8

Tôi muốn viết mã như thế này -Làm thế nào để loại bỏ và thêm các yếu tố vào TreeMap trong khi lặp?

for (Map.Entry<Long, Integer> e : map.entrySet()){ 
    map.remove(k); 
    map.put(x, value); 
} 

nhưng tôi đã nhận java.util.ConcurrentModificationException Tôi cố gắng để sử dụng Iterator cũng nhưng tôi đã cùng Exception

+4

@ZouZou Tôi googled cho điều này và tìm thấy câu hỏi này ngay từ đầu. Google không đủ, nội dung cũng cần :-) – peterh

+0

Bạn có thể đính kèm mã cho trình lặp không. Đoạn mã trên chắc chắn sẽ cung cấp cho bạn một ngoại lệ sửa đổi đồng thời. Bạn đang lặp lại thông qua keyset cũng như sửa đổi bản đồ cùng một lúc. Đây là một công thức cho thảm họa. – SamDJava

+0

Đã thêm câu trả lời dưới đây với mã mẫu. – SamDJava

Trả lời

7

Explaintion tại sao nó gây ra ConcurrentModificationException

map.remove(k); 
map.put(x, value); 

vòng lặp cho mỗi lần cũng tạo nội bộ một trình lặp của entrySet của map. Trong khi lặp qua bản đồ bạn đã sửa đổi cấu trúc của bản đồ bằng cách đặt lại giá trị vào bản đồ (map.put(x,value)) gây ra điều này ConcurrentModificationException.

Người ta thậm chí cũng giải thích trong documentation -

Các vòng lặp được trả về bởi tất cả các lớp học này "xem bộ sưu tập phương pháp" là thất bại nhanh: nếu bản đồ được cấu trúc biến đổi bất cứ lúc nào sau khi iterator được tạo ra, bằng bất kỳ cách nào ngoại trừ thông qua phương thức xóa riêng của trình lặp của , trình lặp sẽ ném một ConcurrentModificationException.Do đó, khi đối mặt với sửa đổi đồng thời, trình vòng lặp không nhanh chóng và sạch sẽ, thay vì rủi ro hành vi tùy ý, không xác định tại thời điểm chưa xác định trong tương lai.

Làm thế nào để giải quyết việc này -

bạn phải thay đổi sự thay đổi cấu trúc của bản đồ này trong khi lặp lại, bạn có thể chèn các giá trị này sau, như giữ một bản đồ tạm thời và thêm một lần lặp xong mình việc làm.

Map<Long, Integer> tempMap = new HashMap<>(); 
for (Map.Entry<Long, Integer> e : map.entrySet()){ 
    map.remove(k); 
    tempMap.put(x, value); 
} 
map.putApp(tempMap); 
1

Bạn sẽ phải tạo ra một bản sao của bản đồ của bạn sử dụng bản sao constructor. Bây giờ lặp lại trên 1 và sửa đổi bản đồ thứ hai. Tôi giả định rằng bạn sẽ không cần phải lặp lại giá trị mới được thêm vào vì nó sẽ không có ý nghĩa nhiều.

Bạn có thể đạt được nhiệm vụ của mình bằng cách tạo bản sao là do các phím sẽ vẫn giữ nguyên trong cả hai.

EDIT:

Tôi không nghĩ rằng nên lặp lại phần tử mới được thêm vào Hashmap. Nếu bạn kiểm tra api được cung cấp bởi Iterator thì bạn sẽ chỉ tìm thấy phương thức remove, không có phương thức add trong nó. Có một lý do đằng sau điều này và bạn có thể kiểm tra javadoc cho việc này. Bây giờ đến thời điểm này, về cách lặp lại phần tử mới được thêm vào.

  1. Tạo bản sao của HashMap. Vì vậy, bạn sẽ lặp lại một và sửa đổi khác Map.
  2. Khi yêu cầu là cả thêm và xóa các phần tử trong Map, tôi muốn sử dụng ListIterator cho điều này [điều này khác với thông thường Iterator].
  3. Tôi sẽ nhận được keyset của Map1 và chuyển đổi nó thành danh sách bằng cách sử dụng ArrayList(Collection<? extends E> c).
  4. Bây giờ tôi sẽ nhận được ListIterator từ bướcđược tạo ở bước 3 và thêm, xóa các phần tử trong ListIterator cũng như trong Map2 [Remeber bạn cần thêm, xóa cả hai trong ListIterator và Map2].
+0

không cần phải lặp lại giá trị mới này giá trị mới được thêm sẽ lớn hơn giá trị hiện tại vì vậy tôi cần phải lặp lại chúng quá –

+0

xem chỉnh sửa của tôi. Sử dụng các bước mới được thêm vào mà bạn có thể thực hiện thêm và xóa cả hai. – Lokesh

0

Vì bạn không thể làm điều đó.

Một giải pháp dễ dàng là sử dụng một bản đồ tạm thời nơi bạn đặt các giá trị bạn muốn và cuối cùng chuyển con trỏ với một bản gốc (tức Bản đồ = newMap)

+0

Tôi cần lặp lại các giá trị mới được thêm –

+0

sau đó tạo một vòng lặp while và tiếp tục thực hiện việc này cho đến khi bạn hoàn tất. – Ahmad

2

lặp trên một bản sao và bạn có thể thêm/gỡ bỏ tốt:

for (Map.Entry<Long, Integer> e : new LinkedHashMap<Long, Integer>(map).entrySet()){ 
    map.remove(k); 
    map.put(x, value); 
} 

Nó thậm chí không bất kỳ dòng nhiều mã, vì ims bản sao thực hiện trong dòng qua constructor sao chép. LinkedHashMap được chọn để duy trì thứ tự lặp lại (nếu điều đó quan trọng).

1

Đoạn mã mẫu để xóa phần tử khỏi bản đồ được đưa ra dưới đây.

for(Iterator<Map.Entry<Long, Integer>> it = map.entrySet().iterator();it.next();) 
{ 
    Map.Entry<String, String> entry = it.next(); 
if(//some logic)  
it.remove(); 
} 

Nếu mã của bạn liên quan đến rất nhiều việc thêm và xóa, bạn có thể chỉ muốn sử dụng ConcurrentHashMap. ConcurrentHashMap

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