1. Klasse ArrayList
In Java ist das Interface List ein Vertrag: „Ich bin eine geordnete Sammlung von Elementen, und man kann bei mir ein Element anhand seiner Nummer (des Index) abrufen.“
Wesentliche Eigenschaften einer Liste (List):
- Elemente werden in einer festen Reihenfolge gespeichert (im Gegensatz zu einer Menge).
- Doppelte Elemente sind erlaubt (zum Beispiel: zweimal "Vasya").
- Zugriff auf ein Element per Index ist möglich: Das erste Element hat den Index 0, das zweite 1 und so weiter.
- Man kann Elemente an beliebiger Stelle der Liste hinzufügen und entfernen.
Die beliebteste Implementierung des Interface List ist die ArrayList. Intern verwendet sie ein gewöhnliches Array und vergrößert sich automatisch mit wachsender Datenmenge.
Wie erstellt man eine ArrayList?
import java.util.ArrayList;
import java.util.List;
public class Example {
public static void main(String[] args) {
// Wir erstellen eine Liste von Strings
List<String> students = new ArrayList<>();
}
}
Erläuterung
- List<String> ist eine Variable vom Typ „Liste von Strings“. Wir deklarieren die Variable über das Interface und erzeugen das Objekt über die konkrete Klasse (ArrayList).
- Die spitzen Klammern <String> legen den Elementtyp der Liste fest (Generics).
Grundlegende Methoden der ArrayList (und generell jeder List):
- add(element) – ein Element ans Ende der Liste hinzufügen.
- add(index, element) – ein Element an einem bestimmten Index einfügen.
- get(index) – ein Element per Index abrufen.
- set(index, element) – ein Element an einem Index ersetzen.
- remove(index) – ein Element an einem Index löschen.
- remove(Object) – das erste gefundene Element löschen, das dem übergebenen Objekt entspricht.
- size() – die Anzahl der Elemente in der Liste ermitteln.
Beispiel: Wir arbeiten mit einer Studentenliste
import java.util.ArrayList;
import java.util.List;
public class StudentListDemo {
public static void main(String[] args) {
List<String> students = new ArrayList<>();
// Studenten hinzufügen
students.add("Vasya");
students.add("Petya");
students.add("Masha");
// Alle Studenten ausgeben
System.out.println("Liste der Studenten: " + students);
// Ersten Studenten abrufen
String first = students.get(0);
System.out.println("Erster Student: " + first);
// Den Namen des zweiten Studenten ändern
students.set(1, "Pavel");
System.out.println("Nach der Änderung: " + students);
// Masha entfernen
students.remove("Masha");
System.out.println("Nach dem Löschen von Masha: " + students);
// Größe der Liste
System.out.println("Anzahl der Studenten: " + students.size());
}
}
Ergebnis:
Liste der Studenten: [Vasya, Petya, Masha]
Erster Student: Vasya
Nach der Änderung: [Vasya, Pavel, Masha]
Nach dem Löschen von Masha: [Vasya, Pavel]
Anzahl der Studenten: 2
Wie hängt das mit unserer Anwendung zusammen?
Angenommen, wir haben eine Anwendung zur Verwaltung der Aufgaben eines Studenten. Dann können wir die Aufgabenliste als List<String> statt als Array speichern und neue Aufgaben dynamisch hinzufügen.
2. Klasse LinkedList: wenn Einfüge- und Löschgeschwindigkeit wichtig ist
LinkedList ist eine alternative Implementierung einer Liste. Sie ist als doppelt verkettete Kette aufgebaut: Jeder Knoten kennt das vorherige und das nächste Element. Wie bei einem Zugverband: Einen „Waggon“ in der Mitte einzukuppeln geht schnell und ohne den ganzen Zug umzuordnen.
Erstellen einer LinkedList
import java.util.LinkedList;
import java.util.List;
public class Example {
public static void main(String[] args) {
List<String> tasks = new LinkedList<>();
}
}
Besonderheiten von LinkedList
- Schnelles Einfügen und Löschen am Anfang und in der Mitte der Liste.
- Langsamer Zugriff per Index (um das 100. Element zu finden, muss die Kette durchlaufen werden).
- Geeignet, wenn Sie Elemente nicht nur am Ende, sondern auch am Anfang oder in der Mitte häufig hinzufügen/entfernen.
Beispiel: LinkedList verwenden
import java.util.LinkedList;
import java.util.List;
public class TaskListDemo {
public static void main(String[] args) {
List<String> tasks = new LinkedList<>();
tasks.add("Aufwachen");
tasks.add("Frühstücken");
tasks.add("Zu den Vorlesungen gehen");
// Aufgabe am Anfang hinzufügen
tasks.add(0, "Wecker stellen");
System.out.println("Aufgabenliste: " + tasks);
// Erste Aufgabe löschen (die früheste)
tasks.remove(0);
System.out.println("Nach dem Löschen der ersten Aufgabe: " + tasks);
}
}
3. Vergleich von ArrayList und LinkedList
| Kriterium | |
|
|---|---|---|
| Basis | Array | Doppelt verkettete Liste |
| Schneller Zugriff per Index | Ja (O(1)) | Nein (O(n)) |
| Schnelles Einfügen/Löschen am Anfang/in der Mitte | Nein (O(n)) | Ja (O(1) – wenn ein Verweis vorhanden ist) |
| Schnelles Einfügen/Löschen am Ende | Ja (meist O(1)) | Ja (O(1)) |
| Speicher | Braucht weniger Speicher | Mehr (zusätzliche Verweise auf Nachbarn) |
| Typische Anwendungsfälle | Häufiger Zugriff per Index | Häufige Einfügungen/Löschungen |
Einfache Faustregel:
- Sie benötigen schnellen Zugriff per Nummer – verwenden Sie ArrayList.
- Sie fügen häufig am Anfang oder in der Mitte hinzu/löschen – verwenden Sie LinkedList.
4. Typische Operationen mit Listen
Iterieren über Listenelemente
Gewöhnliche for-Schleife
for (int i = 0; i < students.size(); i++) {
System.out.println("Student Nr. " + i + ": " + students.get(i));
}
For-each-Schleife (der beliebteste Weg)
for (String name : students) {
System.out.println("Name: " + name);
}
Lambda-Ausdruck (Java 8+)
students.forEach(name -> System.out.println("Name: " + name));
Elemente suchen
- contains(element) – gibt true zurück, wenn das Element in der Liste vorhanden ist.
- indexOf(element) – liefert den Index des ersten Vorkommens des Elements oder -1, wenn es nicht gefunden wurde.
if (students.contains("Vasya")) {
System.out.println("Vasya ist in der Liste!");
}
int index = students.indexOf("Vasya");
System.out.println("Index von Vasya: " + index);
Liste leeren
clear() – löscht alle Elemente.
students.clear();
System.out.println("Liste nach dem Leeren: " + students);
5. Wann verwendet man ArrayList, und wann LinkedList?
Am einfachsten denkt man so: ArrayList ist dort gut, wo man schnell per Index auf Elemente zugreifen muss und sich die Liste nicht oft ändert. Zum Beispiel eine lange Benutzerliste oder ein Nachrichtenverlauf – überwiegend Lesezugriffe.
LinkedList hingegen ist nützlich, wenn Sie ständig Elemente am Anfang/in der Mitte einfügen oder löschen. Das kann eine Warteschlange, ein Stack oder der Verlauf von Rückgängig-Aktionen sein.
In der Praxis wird meist ArrayList verwendet. Und LinkedList bleibt ein „Werkzeug für besondere Fälle“: Es liegt in der Schublade, erweist sich aber gelegentlich genau als das, was man braucht.
6. Häufige Fehler im Umgang mit Listen
Fehler Nr. 1: Zugriff außerhalb der Listen-Grenzen. Die häufigste Situation – Zugriff über einen nicht existierenden Index. Wenn die Liste drei Elemente hat und Sie students.get(5) schreiben, erhalten Sie IndexOutOfBoundsException. Prüfen Sie vor dem Zugriff size().
Fehler Nr. 2: Löschen eines Elements während der Iteration. Beim Durchlaufen mit for-each und gleichzeitigen Löschungen tritt eine ConcurrentModificationException auf. Für komplexere Löschvorgänge verwenden Sie eine Index-Schleife oder Iterator.
Fehler Nr. 3: Falscher Objektvergleich. Wenn Sie eigene Objekte speichern (z. B. Student), verlassen sich die Methoden contains und remove auf equals. Wenn es nicht überschrieben wird, erfolgt der Vergleich nach Referenz statt nach Inhalt.
Fehler Nr. 4: Verwendung roher Typen. Schreiben Sie nicht List list = new ArrayList() – geben Sie immer den Elementtyp an: List<String> list = new ArrayList<>(). Generics schützen vor Fehlern und machen den Code verständlicher.
GO TO FULL VERSION