2013-10-01 17 views
6

Tôi có 2 HashMap<Integer,Point3D> tên đối tượng là positiveCoOrdinate and negativeCoOrdinates.Làm cách nào để khắc phục Ngoại lệ trong chuỗi "chính" java.util.ConcurrentModificationException

Tôi đang kiểm tra PositiveCoOrdinates với điều kiện sau.if nó thỏa mãn điểm tương ứng bổ sung vào negativeCoOrdinates và xóa khỏi positiveCoOrdinates.

HashMap<Integer, Point3d> positiveCoOrdinates=duelList.get(1); 
    HashMap<Integer, Point3d> negativecoOrdinates=duelList.get(2); 
    //condition 
    Set<Integer> set=positiveCoOrdinates.keySet(); 
    for (Integer pointIndex : set) { 
     Point3d coOrdinate=positiveCoOrdinates.get(pointIndex); 
     if (coOrdinate.x>xMaxValue || coOrdinate.y>yMaxValue || coOrdinate.z>zMaxValue) { 
      negativecoOrdinates.put(pointIndex, coOrdinate); 
      positiveCoOrdinates.remove(pointIndex); 
     } 
    } 

Trong khi thêm, xóa thời gian, tôi nhận được lỗi sau.

Exception in thread "main" java.util.ConcurrentModificationException 
at java.util.HashMap$HashIterator.nextEntry(Unknown Source) 
at java.util.HashMap$KeyIterator.next(Unknown Source) 
at PlaneCoOrdinates.CoordinatesFiltering.Integration(CoordinatesFiltering.java:167) 
at PlaneCoOrdinates.CoordinatesFiltering.main(CoordinatesFiltering.java:179) 

Đối với thử nghiệm của tôi, tôi đề cập đến System.out.println(coOrdinate.x); tuyên bố bên mỹ làm việc If condition.it của.

Nếu tôi thêm 2 dòng (Những gì tôi đề cập ở trên) trong điều kiện If, nó sẽ phát ra lỗi.

Làm cách nào để khắc phục sự cố này.

Cảm ơn.

+0

Bạn có thể tránh tìm kiếm khóa mà bạn vừa thu được bằng cách sử dụng 'entrySet()' –

Trả lời

11

Cách đơn giản nhất là để tạo ra một bản sao của keySet:

Set<Integer> set= new HashSet<Integer>(positiveCoOrdinates.keySet()); 

Vấn đề xảy ra bởi vì bạn đang modifing các positiveCoOrdinates trong khi bạn đang sử dụng một Iterator đó lặp thông qua các phím.

Bạn cũng có thể cấu trúc lại mã của mình và sử dụng trình lặp trên tập hợp mục nhập. Đây sẽ là một cách tiếp cận tốt hơn.

Set<Entry<Integer, Point3d>> entrySet = positiveCoOrdinates.entrySet(); 

    for (Iterator<Entry<Integer, Point3d>> iterator = entrySet.iterator(); iterator.hasNext();) { 
     Entry<Integer, Point3d> entry = iterator.next(); 
     Point3d coOrdinate = entry.getValue(); 
     if (coOrdinate.x > xMaxValue || coOrdinate.y > yMaxValue 
       || coOrdinate.z > zMaxValue) { 
      Integer pointIndex = entry.getKey(); 
      negativecoOrdinates.put(pointIndex, coOrdinate); 
      iterator.remove(); 
     } 
    } 
+0

Giao diện tiếp cận tốt. – Woody

+3

Hoặc có thể sử dụng 'Iterator'. – SudoRahul

+0

Cảm ơn nó đang làm việc tuyệt vời ... – Hanumath

0

Nếu bạn muốn sửa đổi bộ sưu tập trong thời gian chạy, bạn cần sử dụng Iterator thay vì tăng cường cho vòng lặp. Vì tăng cường cho vòng lặp chỉ cung cấp chức năng chỉ đọc. Sau đây là ví dụ Iterator:

Iterator<Entity> iterator = collection.Iterator(); 
while(iterator.hasNext()){ 
    //DO Your Stuff 
    iterator.remove(); // this function call remove the element from collection at run time 
} 
2

Bạn không remove() từ bộ sưu tập lặp có thể khi sử dụng tăng cường for-each vòng lặp. Vòng lặp for-each sử dụng hoàn toàn Iterator<Integer>. Các JavaDoc nêu rõ rằng

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, trong bất kỳ cách nào ngoại trừ thông qua phương thức remove() của trình lặp riêng, trình lặp sẽ ném một số 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.

Vòng lặp for-each tạo một trình lặp nội bộ và sử dụng trình vòng lặp này để đi qua bộ này. Sau đó, bạn thay đổi cấu trúc của tập hợp ... và trình vòng lặp phải thất bại. Vấn đề là bạn không có quyền truy cập vào các phương thức của trình lặp, vì vậy bạn phải sử dụng một cách rõ ràng Iterator<Integer>. Đoạn mã bytecode được tạo sẽ giống nhau, khác biệt duy nhất là bạn có thể xóa các phần tử khỏi danh sách khi bạn duyệt qua nó.

Set<Integer> set = positiveCoOrdinates.keySet(); 
for (Iterator<Integer> iterator = set.iterator(); iterator.hasNext();) { 
    Integer pointIndex = iterator.next(); 
    Point3d coOrdinate = positiveCoOrdinates.get(pointIndex); 
    if (coOrdinate.x>xMaxValue || coOrdinate.y>yMaxValue || coOrdinate.z>zMaxValue) { 
     negativecoOrdinates.put(pointIndex, coOrdinate); 
     iterator.remove(pointIndex); // this line changed! 
    } 
} 

Nếu bạn không quen thuộc với vòng lặp và chức năng của họ, xem the Oracle tutorial on Collections:

Một Iterator được một đối tượng cho phép bạn đi qua thông qua một bộ sưu tập và để loại bỏ các yếu tố từ bộ sưu tập có chọn lọc, nếu mong muốn. Bạn nhận được một Iterator cho một bộ sưu tập bằng cách gọi phương thức iterator() của nó.

Lưu ý rằng Iterator.remove() là cách an toàn duy nhất để sửa đổi bộ sưu tập trong khi lặp lại; 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 đang lặp lại .

Sử dụng Iterator thay vì for-each xây dựng khi bạn cần phải:

  • Tháo tử hiện hành. Cấu trúc for-each ẩn trình lặp, do đó bạn không thể gọi remove(). Do đó, cấu trúc for-each không thể sử dụng để lọc.
0

Do René lý do cho vấn đề rất phổ biến này là sửa đổi đồng thời với bộ sưu tập trong khi nó đang được đọc bởi người khác.

Bạn có thể sử dụng ConcurrentHashMap hoặc bộ sưu tập như CopyOnWriteArrayLit, nhưng hãy cẩn thận rằng những phương pháp tiếp cận có thể là một chút expensive và đổi đơn giản để mã hóa để loại bỏ đọc của bộ sưu tập cùng khi trong một lần lặp sẽ giải quyết loại này vấn đề.

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