2013-08-05 6 views
5

Я столкнулся с очень странным поведением Java, и я не знаю, является ли это ошибкой, или . Я что-то упускаю.Исключение Nullpointer в LinkedList при использовании для каждого цикла

Код просто проходит через список 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?

/* Update */

уничтожить() вызов не изменяет stateStack. Если бы я догадался, что Java будет throw ConcurrentModificationException.

stateStack был заселен одним состоянием, которое отменяет уничтожение, но только местных модификаций. Супер-реализация, чем печать дополнительного журнала («Destroying state ...»), которого не было в файле журнала, поэтому я думаю, что исключение было отправлено в в начале итерации.

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

Где находится строка ': 132'? Может быть, 'state' в вашем списке« null »? – Manuel

+0

Как и где вы получаете stateStack? – arjacsoh

+3

Какова реализация 'state.destroy()'. Что оно делает? Кроме того, как заполняется «stateStack»? – mthmulders

ответ

6

Часть кода ниже генерирует то же исключение почти каждый раз, когда я запускаю его - идея состоит в том, чтобы изменить список при повторении из другого потока. С (не) удачным временем модификация происходит после checkForComodification, но до next = next.next; в методе ListItr#next, вызывая NPE.

Исключение в потоке "основного" java.lang.NullPointerException в java.util.LinkedList $ ListItr.next (LinkedList.java:891) в 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

Это внутренняя реализация 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 происходит потому, что внутренняя переменная next является null; однако, кажется, что hasNext() подтверждает, что существует следующий элемент.

Мне кажется, что:

  • у вас есть более чем одна нить изменения списка, ИЛИ
  • вы изменяете свой список в реализации destroy() в то время как итерация по списку.

Если вы обновляете свой ответ с вашей реализацией destroy(), как мотивационный по @mthmulders, я либо обновление, исправить или удалить мой ответ.

Смежные вопросы