4.03 ArrayList

Einleitung

Wir wollen und hier eine Alternative zu Arrays ansehen, die den Vorteil bietet, dass ihre Größe variabel ist. Da wir zum Verständnis dieser Alternative mit Klassen, Objekten und auch Wrapperklassen vertraut sein sollten, haben wir sie uns nicht früher angesehen.

In Wahrheit gibt es eine ganze Reihe von Alternativen, die sich zum Teil sehr ähneln. Um hier den Rahmen nicht zu sprengen, beschränken wir uns auf die Klasse ArrayList. Am Ende werfen wir nur einen ganz kurzen Blick auf die eine weitere Alternative.

Anlegen einer ArrayList

import java.util.ArrayList;

public class ListDemo {

    public static void main(String[] args) {

        ArrayList<Integer> meineListe = new ArrayList<>();

        meineListe.add(2);
        meineListe.add(3);
        meineListe.add(5);
        meineListe.add(7);
        meineListe.add(11);
        meineListe.add(13);
        meineListe.add(17);
        meineListe.add(19);
        meineListe.add(23);
        meineListe.add(29);
        meineListe.add(31);

        System.out.println(meineListe);
        // Ausgabe: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
        
        ArrayList<String> meineStringList;
        meineStringList = new ArrayList<>();
        
        meineStringList.add("Hallo!");
        meineStringList.add("Das ist ein Test!");
        
        System.out.println(meineStringList);
        // Ausgabe:[Hallo!, Das ist ein Test!]

    }

}

Wie wir sehen, wird beim Deklarieren einer Array-List in spitzen Klammern die Klasse angegeben, von der Instanzen in der Liste gespeichert werden sollen. In der ersten Liste werden Instanzen von Integer gespeichert, in der zweiten Instanzen von String.
Natürlich könnten wir auch Instanzen einer von uns selbst erstellten Klasse in einer Liste ablegen.

Beim Aufruf des Konstruktors der Klasse ArrayList müssen wir noch einmal die spitzen Klammern schreiben. Dort dürfen wir die Klammern aber leer lassen.
Wir könnten in den runden Klammern eine Startkapazität der Liste angeben, falls wir bereits wissen, wie viele Elemente zu Beginn eingefügt werden sollen. Das ist aber nicht Pflicht.

Mit der add-Methode können wir eine Liste dann nach und nach füllen. Verwenden wir diese Methode, werden die neuen Elemente immer ganz hinten an die Liste angefügt.

Erfreulich ist, dass wir eine solche Liste einfach in eine System.out.print-Anweisung stecken können, um uns anzeigen zu lassen, was sie momentan enthält.

Methoden von ArrayList

Sehen wir uns ein Beispiel für die Verwendung verschiedener Methoden an:

import java.util.ArrayList;

public class ListDemo {

    public static void main(String[] args) {

        ArrayList<Integer> meineListe = new ArrayList<>();

        System.out.println(meineListe.isEmpty());
        // Ausgabe: true

        meineListe.add(2);
        meineListe.add(3);
        meineListe.add(5);
        meineListe.add(7);
        meineListe.add(11);
        meineListe.add(13);
        meineListe.add(17);
        meineListe.add(19);
        meineListe.add(23);
        meineListe.add(29);
        meineListe.add(31);

        System.out.println(meineListe);
        // Ausgabe: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]

        System.out.println(meineListe.isEmpty());
        // Ausgabe: false

        System.out.println(meineListe.size());
        // Ausgabe: 11

        System.out.println(meineListe.get(3));
        // Ausgabe: 7

        meineListe.add(0, 101);
        System.out.println(meineListe);
        // Ausgabe: [101, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]

        meineListe.remove(1);
        System.out.println(meineListe);
        // Ausgabe: [101, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]

        meineListe.set(0, 2);
        System.out.println(meineListe);
        // Ausgabe: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]

        System.out.println(meineListe.indexOf(5));
        // Ausgabe: 2

        System.out.println(meineListe.indexOf(6));
        // Ausgabe: -1

        meineListe.clear();
        System.out.println(meineListe);
        // Ausgabe: []        

    }

}

Wir sehen hier die folgenden Methoden:

Methode Funktion
isEmpty() Liefert true, falls die Liste leer ist.
Sonst wird false geliefert.
size() Liefert die aktuelle Anzahl von Elementen als int-Wert.
get(int position) Liefert das Element, das an der Stelle position liegt.
Wie bei Arrays beginnt man bei 0 zu zählen.
add(int pos, neu) Fügt vor das Element an Stelle pos das Element neu ein.
remove(int pos) Löscht das Element an Stelle pos.
Es entsteht aber keine Lücke.
set(int pos, neu) Ersetzt das Element an Stelle pos durch neu.
indexOf(element) Gibt an, wo element erstmals in der Liste auftritt.
Tritt es gar nicht auf, wird -1 geliefert.
clear() Löscht alle Einträge.

Schleifen

Oftmals ist es sehr hilfreich, mit einer Schleife alle Elemente einer Liste zu durchlaufen. Dies haben wir ja auch schon bei Arrays gesehen.

Sehen wir uns zunächst eine weniger elegante aber uns dafür eher vertraute Möglichkeit an – sie sollte uns stark an das Durchlaufen eines Arrays erinnern.

import java.util.ArrayList;

public class ListDemo {

    public static void main(String[] args) {

        ArrayList<Integer> meineListe = new ArrayList<>();

        meineListe.add(2);
        meineListe.add(3);
        meineListe.add(5);        
        meineListe.add(7);
        meineListe.add(11);
        meineListe.add(13);
        meineListe.add(17);
        meineListe.add(19);
        meineListe.add(23);
        meineListe.add(29);
        meineListe.add(31);

        for (int i = 0; i < meineListe.size(); i = i + 1) {
            System.out.println((i + 1) + "te Primzahl: " + meineListe.get(i));
        }

    }

}

Wie sonst bei Arrays verwenden wir hier eine Zählschleife. Der Zähler läuft von 0 bis zu eins weniger als die Größe der Liste. In jedem Durchlauf wird mit get auf das Element an der aktuellen Stelle zugegriffen.

Wie schon gesagt, kommt uns dies sehr vertraut vor. Die schönere Variante ist aber diese:

import java.util.ArrayList;

public class ListDemo {

    public static void main(String[] args) {

        ArrayList<Integer> meineListe = new ArrayList<>();

        meineListe.add(2);
        meineListe.add(3);
        meineListe.add(5);        
        meineListe.add(7);
        meineListe.add(11);
        meineListe.add(13);
        meineListe.add(17);
        meineListe.add(19);
        meineListe.add(23);
        meineListe.add(29);
        meineListe.add(31);

        for (Integer aktuelle : meineListe) {
            System.out.println("Eine Primzahl: " + aktuelle);
        }
    }

}

Dies ist eine sogenannte for-each-Schleife. Die Anweisung for (Integer aktuelle : meineListe) könnte man nämlich lesen als „für jede Integer aktuelle aus meineListe“. Dabei ist aktuelle ein vollkommen beliebiger Name.

Zusatzbemerkungen für Neugierige

Eine Alternative und das Interface List

Die Klasse ArrayList ist in Wahrheit „nur“ eine mögliche Implementierung des Interfaces List. All die Methoden, die ArrayList anbietet, sind Methoden, die in diesem Interface bereits vorgeschrieben werden.

Eine Array-List verwendet intern ein Array, um die Elemente zu speichern. Wird das Array durch Hinzufügen neuer Elemente zu klein, wird es einfach durch ein größeres ersetzt. Umgekehrt kann es auch verkleinert werden.
All diese technischen Schwierigkeiten sind für uns aber unsichtbar und können uns damit gleichgültig sein. Nur der Name Array-List wird damit natürlich plausibel.

Es gibt aber auch noch andere Wege, die in List verlangten Methoden zu implementieren. Einen vollkommen anderen Ansatz beschreitet die Klasse LinkedList. Diese verkettet die eingefügten Elemente automatisch untereinander, so dass sie in einer Reihe angeordnet werden.
Das kommt übrigens der Klasse List, die in NRW im Zentralabitur verwendet wird, recht nahe!

Da dies beides letztlich zwei Umsetzungen derselben Idee sind, liest man in der Literatur, dass es eleganter ist, eine Liste mit List<Integer> meineListe = new ArrayList<>(); zu deklarieren. Dies kann man lesen als: „Ich brauche eine List und entscheide mich für die Implementierung ArrayList.“

Iteratoren

Mit einem sogenannten Iterator haben wir noch eine Alternative zur for-each-Schleife. Allerdings ist die for-each-Schleife die moderne und wenige für Programmierfehler anfällige Variante!

Eine nette Beobachtung zu Iteratoren gibt es aber:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListDemo {

    public static void main(String[] args) {

        List<Integer> meineListe = new ArrayList<>();

        meineListe.add(2);
        meineListe.add(3);
        meineListe.add(5);
        meineListe.add(7);
        meineListe.add(11);
        meineListe.add(13);
        meineListe.add(17);
        meineListe.add(19);
        meineListe.add(23);
        meineListe.add(29);
        meineListe.add(31);

        Iterator<Integer> meinIterator = meineListe.iterator();

        System.out.println("Die Primzahlen unter 10:");
        Integer zahl = 0;
        while (zahl <= 5) {
            zahl = meinIterator.next();
            System.out.println(zahl);
        }

        System.out.println("Und nun noch ein paar:");
        while (meinIterator.hasNext()) {
            zahl = meinIterator.next();
            System.out.println(zahl);
        }

    }
}

Ein solcher geht nach und nach durch die Liste und merkt sich, welches Element wir uns gerade angesehen haben. Mit next() liefert es das nächste und rückt eine Position weiter.
Unterbrechen wir das Durchlaufen einer Liste, merkt er sich automatisch wo wir stehen geblieben sind!

Ob dieser Vorteil tatsächlich mal zu tragen kommt, mag ich hier nicht beurteilen. Da dies aber an das Konzept des Laufzeigers der in NRW verwendeten Abiturklasse List erinnert, wollte ich dies hier dennoch einmal kurz vorstellen.

 

 

Ein Gedanke zu „4.03 ArrayList“

Kommentare sind geschlossen.