2012-05-06 27 views
6

Właśnie przekazałem wszystkie moje tablice do ArrayList (z powodu mojego wielkiego braku wiedzy w Javie nie wiedziałem, że podstawowy typ tablicy nie ma żadnego ".add" opcja) w moim małym programem i wszystko wydaje się dobrze ... oprócz tego, że od czasu do czasu jest wyjątek, ale zaprzecza się:Kolejny wyjątek java.lang.IndexOutOfBoundsException, ale indeks <rozmiar

Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 17, Size: 21 
    at java.util.ArrayList.rangeCheck(ArrayList.java:604) 
    at java.util.ArrayList.get(ArrayList.java:382) 
    at guay.Puntitos.AumentarTamano(Puntitos.java:346) 
    at guay.Guay$MiMouse.mouseMoved(Guay.java:226) 
    at java.awt.Component.processMouseMotionEvent(Component.java:6550) 
    at java.awt.Component.processEvent(Component.java:6274) 
    at java.awt.Container.processEvent(Container.java:2229) 
    at java.awt.Window.processEvent(Window.java:2016) 
    at java.awt.Component.dispatchEventImpl(Component.java:4861) 
    at java.awt.Container.dispatchEventImpl(Container.java:2287) 
    at java.awt.Window.dispatchEventImpl(Window.java:2713) 
    at java.awt.Component.dispatchEvent(Component.java:4687) 
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:707) 
    at java.awt.EventQueue.access$000(EventQueue.java:101) 
    at java.awt.EventQueue$3.run(EventQueue.java:666) 
    at java.awt.EventQueue$3.run(EventQueue.java:664) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) 
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87) 
    at java.awt.EventQueue$4.run(EventQueue.java:680) 
    at java.awt.EventQueue$4.run(EventQueue.java:678) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) 
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:677) 
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:211) 
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128) 
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105) 
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:90) 

blok kodu Java wskazać mi to:

for (int i = 1; i < elipsasCol.size(); i++) { 
    if (elipsasCol.get(i) != null && elipsasCol.get(i).contains(mouse)) { 
    // This line      
    double modulo = Math.sqrt(Math.pow(mouse.x - elipsasCol.get(i).getCenterX(), 2) 
          + Math.pow(mouse.y - elipsasCol.get(i).getCenterY(), 2)); 
    } 
} 

Błąd nie powoduje żadnych problemów z wydajnością programu. Byłbym jednak wdzięczny, że ktoś może mi wyjaśnić, co jest przyczyną tego wyjątku.

Dziękujemy!

+1

możesz chcieć uruchomić pętlę na 0, chyba że jest to wartość specjalna ... –

+0

Czy istnieje konkretny powód, dla którego twoja pętla zaczyna się @ 1, a nie 0? –

+2

Czy istnieje powód, dla którego nie używasz [dla każdej pętli] (http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html)? – amit

Odpowiedz

11

To będzie problem z jednoczesną modyfikacją. Jest to jedyny sposób, w jaki można uzyskać ten błąd.

Powodem, dla którego nie otrzymasz błędu modyfikacji współbieżnej jest to, że sposób, w jaki robisz przejście przez pętlę, nie tworzy iteratora i jako taki nie daje szansy na zgłoszenie współbieżnego błędu modyfikacji.

Proponuję synchronizację na twojej liście macierzy lub używając czegoś takiego jak CopyOnWriteArrayList .

Edycja: Przepraszamy CopyOnWrite nie będzie działać w przypadku tego konkretnego problemu. Musisz przełączyć się na pętlę foreach, aby była to opcja.

W odpowiedzi na Twój komentarz poniżej:

Synchronizacja:

synchronized(elipsasCol){ 
for (int i = 1; i < elipsasCol.size(); i++) { 
    if (elipsasCol.get(i) != null && elipsasCol.get(i).contains(mouse)) { 
    // This line      
    double modulo = Math.sqrt(Math.pow(mouse.x - elipsasCol.get(i).getCenterX(), 2) 
          + Math.pow(mouse.y - elipsasCol.get(i).getCenterY(), 2)); 
    } 
} 

a następnie dodać podobną synchronized(elipsasCol){} wokół nigdzie indziej dotknąć elipsasCol.

lub

for (T obj : elipsasCol) { 
    if (obj != null && obj.contains(mouse)) { 
    // This line      
    double modulo = Math.sqrt(Math.pow(mouse.x - obj.getCenterX(), 2) 
          + Math.pow(mouse.y - obj.getCenterY(), 2)); 
    } 
} 

który najprawdopodobniej przyczyną błędu concurrentmodification zostać wyrzucony. W tym momencie możesz przełączyć ArrayList na CopyOnWriteArrayList lub zsynchronizować wokół niego.

+2

Czy będzie działać bez każdej pętli? Jak rozumiem z javadoc 'CopyOnWriteArrayList' pomaga przy tworzeniu nowego iteratora (używamy go dla każdej pętli). Czy to jest poprawne? –

+1

@NikitaBeloglazov masz rację. Musi przełączyć się na a dla każdej pętli, a następnie może użyć kopii przy zapisie, aby uniknąć jednoczesnego problemu modyfikacji, który otrzyma. Zmieniłem moją odpowiedź, aby to odzwierciedlić. – Krrose27

+0

Wowow, to przewyższa mój amatorski poziom java, czas na naukę;) – LosTChG