Programmierung
Ansicht oder Kopie?
Es lohnt sich oft, den Vertrag einer Methode zu lesen, also die Dokumentation, welche die Methode, ihre Argumente, ihre Rückgabe und die Auswirkung auf den Status des Objektes beschreibt. Bei manchen Methoden von Java-Collection-Klassen ist das besonders wichtig, denn sie liefern nicht unbedingt das, was der Name der Methode suggeriert. Z.B. gibt die Methode subList
von java.util.List
keine Teilkopie, sondern eine Ansicht der Instanz zurück, auf der sie aufgerufen wird. Die zurückgegebene Teilliste zeigt auf einen Teil der ursprüngliche Liste, der durch die angegebenen Indizes begrenzt wird, ist also keine Kopie. Welche Konsequenzen dies hat, veranschaulicht folgendes Beispiel, bei welchem auf eine Liste von Zeichenketten wie auf einen Stapel zugegriffen wird.
List<String> list = new LinkedList<String>();
public List<String> popItems( final int maxItems ) {
// consider how many items are there
int k = maxItems < list.size() ? maxItems : list.size();
// (!!!) get the first k items (!!!)
final List<String> subList = list.subList( 0, k );
// remove retrieved items from the list
list.removeAll( subList );
// return the requested items
return subList;
}
Die Ausführung des Codes führt zu einer Ausnahme: ConcurrentModificationException
. Die ursprüngliche Liste darf nämlich nach dem Aufruf von subList
, solange die Teilliste existiert (erreichbar ist), nicht strukturell verändert werden. Es dürfen dieser also keine Elemente weggenommen oder hinzugefügt werden. Strukturelle Änderungen sind nur über die erhaltene Ansicht möglich, weil diese sonst möglicherweise korrumpiert würde. Das obige Code-Schnipsel ist allerdings leicht zu reparieren, indem wir einfach den Geltungsbereich der Teilansicht begrenzen. Statt die Ansicht direkt zu verwenden, erzeugen wir mit dieser eine alleinstehende Kopie.
// (!!!) make a copy of the first k items (!!!)
final List<String> subList
= new LinkedList<String>( list.subList( 0, k ) );
Ebenso ist übrigens auch eine Liste, die mit java.util.Arrays.asList
erzeugt wurde, nur eine Ansicht des Feldes, das als Argument übergeben wurde. Die Komplementärmethode java.util.List.toArray
dagegen erzeugt in jedem Fall ein neues Feld. Folgendes Code-Schnipsel ist demnach eine umständliche Art – wer sein Rahmenwerk kennt, benutzt dafür natürlich Arrays.copyOf
– eine Kopie von einem Feld anzulegen.
String[] stringArray = {"eins", "zwei", "drei"};
// create a List view of the array
List stringList = Arrays.asList( stringArray );
// copy the list (and its backing array)
String[] arrayCopy = (String[]) stringList.toArray();
Es ist ressourcenschonend, eine Ansicht einer Collection zu verwenden, manchmal jedoch ist es notwendig, eine Kopie anzulegen.