2016-07-07 19 views
0

Dies ist die nächste Methode der Arraylist :: Itrist i> = elementData.length in ArrayList :: iterator redundant?

public E next() { 
    checkForComodification(); 
    int i = cursor; 
    if (i >= size) 
     throw new NoSuchElementException(); 
    Object[] elementData = ArrayList.this.elementData; 
    if (i >= elementData.length) 
     throw new ConcurrentModificationException(); 
    cursor = i + 1; 
    return (E) elementData[lastRet = i]; 
} 

Es hat eine if-Anweisung enthält:

if (i >= elementData.length) 
    throw new ConcurrentModificationException(); 

Ich denke, es ist selten, dass i >= elementData.length Zustand passieren, es sei denn, Benutzer TrimToSize Methode aufrufen. Und ich denke, die if-Anweisung ist redundant, weil checkForCodification alles verarbeiten kann. Bin ich richtig?

+1

Ich denke, dass Sie nicht "reichlich" bedeuten ... weil es keinen Sinn ergibt. Meinst du "überflüssig"? –

+0

Ja, vielen Dank. – expoter

+0

* "Habe ich Recht?" * Nein, weil Sie nicht die Garantie haben, dass man den Inhalt nicht nach 'checkForCodification', sondern vor 'if (i> = elementData.length)' manipuliert. Sie werden viele Fälle finden, wenn Sie nach * "Java ConcurrentModificationException Iterator" * googlen. – Tom

Antwort

1

Nein, ist es nicht. Wenn ein anderer Thread solche verwendet wird, dass die ArrayList ‚s trimTosize wurde nach verwendete

checkForComodification(); 

... aber bevor die

Object[] elementData = ArrayList.this.elementData; 

ArrayList.this.elementData wurden geändert kann (hat ein neues Array Referenz) in der Zwischenzeit. Es ist also richtig und notwendig zu überprüfen, ob der Index im Array nach in einer lokalen Variablen (elementData) gültig ist. Nachdem der Code das getan hat, hat er einen lokalen Verweis auf das Array, in dem er suchen wird (elementData) und eine lokale Variable für den Index i). Der Code ist an diesem Punkt notwendig, um die korrekte Ausnahme (ConcurrentModificationException) anstelle von ArrayIndexOutOfBounds zu werfen, wenn eine Änderung an ArrayList.this.elementData vor dem Codegriff den Index ungültig gemacht hat.

Z. B. beachten Sie die ** Linien:

public E next() { 
     checkForComodification(); 
     int i = cursor;         // *** 
     if (i >= size)          // *** 
      throw new NoSuchElementException();   // *** 
     Object[] elementData = ArrayList.this.elementData; // *** 
     if (i >= elementData.length) 
      throw new ConcurrentModificationException(); 
     cursor = i + 1; 
     return (E) elementData[lastRet = i]; 
    } 

Der andere Faden dort kommen könnte. Erst wenn wir unseren eigenen Verweis auf das Array haben, das wir verwenden werden (sobald die letzte ** Zeile fertig ist), wissen wir, dass sich die Referenz nicht ändert (da sie lokal ist).

+0

Ich denke deine Antwort ist teilweise korrekt. Es stimmt, dass ArrayIndexOutOfBounds ohne "i> = elementData" passieren kann.length "check. Aber diese Prüfung kann nicht garantieren, dass ArrayIndexOutOfBounds nie passieren wird, weil elementData size auch nach" cursor = i + 1; "vor" return "durch einen anderen Thread geändert werden kann. Also denke ich, dass die Länge überprüft wird ist sinnlos, oder? – expoter

+1

@expoter: Nein, das kann nicht sein. Der Inhalt eines Arrays ist veränderbar, aber die Länge des Arrays ist nicht. Wie der 'Object [] elementData = ArrayList.this.elementData;' line Ich habe darauf hingewiesen, dass unsere lokale Variable 'elementData' sich nicht auf ein anderes Array zwischen' if (i> = elementData.length) 'und' return (E) elementData [lastRet = i] beziehen kann; 'Das wissen wir auch ' "' ArrayList.this.elementData' ** kann jedoch geändert werden, um auf ein anderes Array zu zeigen. Also ist die Überprüfung sowohl notwendig als auch ausreichend. –

+1

Oh, ich Habe ich, danke. – expoter

0

Angenommen, Sie meinen "redundant" nicht "reichlich", dann ist es nicht.

Es gibt ein kleines (kleines) Fenster nach der Aufruf an checkForComodification(), in dem die Größe des Arrays geändert werden kann, weil ein anderer Thread die ArrayList Größe verändert hat. Die Wahrscheinlichkeit, dass dies passiert, ist sehr gering, aber wenn diese Überprüfung nicht da war, könnte der next() Anruf eine ArrayIndexOutOfRangeException werfen.


Die Kehrseite ist, dass der next() Code nicht alle gleichzeitig Änderungen erkennen garantiert. Wenn ein anderer Thread nach dem Aufruf checkForComodification() ein Element zur Liste hinzugefügt hat, wird diese Änderung nicht erkannt.