2013-08-05 104 views
5

我遇到了非常奇怪的Java行爲,我不知道它是否是一個bug,或者我錯過了一些東西 。LinkedList中的空指針異常在使用for-each循環時

代碼只是通過stateStack(LinkedList)列表並銷燬所有狀態。

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

    // ... 
} 

以下異常被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) 
    // ... // 

此代碼通常工作沒有問題,並且已經在生產了一年多。

這可能是Java錯誤嗎?

/*更新*/

destroy()方法調用不修改stateStack。如果是這樣,我猜Java將 拋出ConcurrentModificationException。

stateStack被填充了1個狀態,這會覆蓋銷燬,但僅對 進行局部修改。超級實現打印另外的日誌(「銷燬狀態...」),這不在日誌文件中,所以我猜這個異常是在迭代開始時拋出的 。

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

line':132'在哪裏?也許你的列表中的'state'是'null'? – Manuel

+0

如何以及在哪裏獲得stateStack? – arjacsoh

+3

'state.destroy()'的實現是什麼?它有什麼作用?另外,'stateStack'如何填充? – mthmulders

回答

6

下面的代碼片段幾乎每次運行時都會生成相同的異常 - 這個想法是在從另一個線程迭代的同時修改列表。使用(非)幸運時機,修改發生在checkForComodification之後,但在next = next.next;之前發生在ListItr#next方法中,導致NPE。

在javaapplication4.Test1.main(Test1.java:74)在java.util.LinkedList中的$ ListItr.next(LinkedList.java:891) 線程 「主」 顯示java.lang.NullPointerException 異常

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

這是內部執行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; 
} 

NullPointerException是因爲內部變量nextnull;但是,似乎hasNext()正在驗證是否存在下一個元素。

在我看來是:

  • 你有一個以上的線程修改您的列表或
  • 要修改列表中的destroy()實施,同時遍歷列表。

如果你更新了你的答案,你的執行destroy()被@mthmulders消化,我會更新,更正或刪除我的答案。