2013-08-05 28 views
5

tôi đi qua hành vi Java rất kỳ quặc, và tôi không biết nếu nó là một lỗi, hoặc tôi thiếu cái gì đó.Nullpointer ngoại lệ trong LinkedList trong khi sử dụng for-each loop

Mã đơn giản đi qua danh sách stateStack (LinkedList) và hủy tất cả các trạng thái.

public void clearStates() 
{ 
    LogFactory.getLog(StateController.class.getName()) 
     .info("Clearing states. #ofstates="+stateStack.size()); 
    for (State state : stateStack) // Line 132 (see exception) 
    { 
     state.destroy(); 
    } 

    // ... 
} 

Trường hợp ngoại lệ sau đây được trowed:

INFO controllers.StateController : Clearing states. #ofstates=1 
java.lang.NullPointerException\ 
    at java.util.LinkedList$ListItr.next(LinkedList.java:891) 
    at *.controllers.StateController.clearStates(StateController.java:132) 
    // ... // 

Mã này thường làm việc mà không có một vấn đề và đã được sản xuất trong hơn một năm.

Có thể đây là lỗi Java không?

/* Cập nhật */

tiêu diệt() gọi không thay đổi stateStack. Nếu tôi đoán Java sẽ ném ConcurrentModificationException.

stateStack được điền với 1 trạng thái, ghi đè phá hủy, nhưng chỉ sửa đổi cục bộ. Việc triển khai siêu hơn bản ghi nhật ký bổ sung ("Trạng thái phá hủy ..."), không có trong tệp nhật ký, vì vậy tôi đoán ngoại lệ được ném tại số bắt đầu lặp lại.

public void destroy() 
{ 
    destroyed = true; 
    LogFactory.getLog(State.class.getName()).info("Destorying state : "+getClass().getName()); 
    propertyChangeSupport.firePropertyChange(PROP_DESTROYED, null, this); 
} 
+0

Dòng ở đâu ': 132'? Có thể 'state' trong danh sách của bạn là' null'? – Manuel

+0

Làm thế nào và ở đâu để bạn có được stateStack? – arjacsoh

+3

Việc thực thi 'state.destroy()' là gì. Nó làm gì? Ngoài ra, 'stateStack' được điền như thế nào? – mthmulders

Trả lời

6

Các đoạn mã dưới đây tạo ra cùng một ngoại lệ hầu như mỗi khi tôi chạy nó - ý tưởng là để sửa đổi danh sách trong khi lặp lại từ thread khác. Với (un-) thời gian may mắn, sửa đổi xảy ra sau checkForComodification nhưng trước next = next.next; theo phương pháp ListItr#next, gây ra lỗi NPE.

Exception in thread "main" java.lang.NullPointerException tại java.util.LinkedList $ ListItr.next (LinkedList.java:891) tại javaapplication4.Test1.main (Test1.java:74)

public class Test { 
    public static void main(String[] args) { 
     final int SIZE = 100000; 
     final Random rand = new Random(); 
     final List<Integer> list = new LinkedList<>(); 
     for (int i = 0; i < SIZE; i++) { 
      list.add(i); 
     } 

     Runnable remove = new Runnable() { 

      @Override 
      public void run() { 
       while (true) { 
        int i = rand.nextInt(SIZE); 
        list.remove(i); 
        try { 
         Thread.sleep(10); 
        } catch (InterruptedException ex) { 
         break; 
        } 
        list.add(i); 
       } 
      } 
     }; 
     Thread t = new Thread(remove); 
     t.start(); 
     for (int i = 0; i < 100; i++) { 
      try { 
       for (Integer j: list) { 
        ///whatever 
       } 
      } catch (ConcurrentModificationException e) { 
      } catch (NullPointerException e) { 
       e.printStackTrace(); 
      } 
     } 
     t.interrupt(); 
    } 
} 
6

này là việc thực hiện nội bộ của LinkedList.ListItr.next():

public E next() { 
    checkForComodification(); 
    if (!hasNext()) 
     throw new NoSuchElementException(); 

    lastReturned = next; 
    next = next.next; // your stacktrace says the NullPointerException happens here 
    nextIndex++; 
    return lastReturned.item; 
} 

Các NullPointerException xảy ra vì nội biến nextnull; tuy nhiên, có vẻ như hasNext() đang xác thực rằng có một yếu tố tiếp theo.

Dường như với tôi rằng:

  • bạn có nhiều hơn một thread sửa đổi danh sách của bạn, HOẶC
  • bạn đang chỉnh sửa danh sách của bạn trong việc thực hiện destroy() khi iterating trên danh sách.

Nếu bạn cập nhật câu trả lời với việc triển khai destroy() như sugested bởi @mthmulders, tôi cập nhật, sửa hoặc xóa câu trả lời của tôi.

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