Zum Inhalt
wannacode

Listen

Kurz gesagt: Eine Liste ist eine Collection, die von selbst wächst und schrumpft; ArrayList hält die Elemente der Reihe nach wie ein Array, und List<String> sagt, welchen Typ sie haben.

Problem

Der Warenkorb ist voll

Du schreibst den Warenkorb eines Onlineshops und hältst die Artikel in einem Array. Aber ein Array hat eine Größe, die sich nicht ändert. Legt der Kunde einen vierten Artikel hinein, legst du ein größeres Array an und kopierst alles. Nimmt er einen Artikel heraus, bleibt eine Lücke:

String[] cart = { "Brot", "Milch", "Kaffee" };
// Ein vierter Artikel: Das Array ist voll, also legen wir ein größeres an und kopieren.
String[] bigger = new String[cart.length + 1];
for (int i = 0; i < cart.length; i++) {
bigger[i] = cart[i];
}
bigger[cart.length] = "Butter";
cart = bigger;
// Der Kunde nimmt die Milch heraus.
cart[1] = null;
for (String item : cart) {
System.out.println(item);
}
Ausgabe
Brot
null
Kaffee
Butter
Jetzt muss jede Schleife über den Warenkorb null überspringen. Und die Zahl der Artikel ist nicht mehr cart.length.

Das ist viel Code für etwas, das jeder Shop ständig macht.

Die Idee

ArrayList: ein Array, das sich selbst kümmert

Java hat dafür eine fertige Klasse: ArrayList. Sie hält die Elemente in einem Array, erledigt das Kopieren und Verschieben aber selbst. So eine Collection heißt Liste:

Main.java
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<String> cart = new ArrayList<>();
cart.add("Brot");
cart.add("Milch");
cart.add("Kaffee");
cart.add("Butter");
cart.remove("Milch");
System.out.println(cart);
System.out.println("Artikel: " + cart.size());
}
}
Ausgabe
[Brot, Kaffee, Butter]
Artikel: 3
  • ArrayList liegt im Paket java.util, darum beginnt die Datei mit einem import, wie bei Scanner.
  • add hängt hinten an, und remove entfernt und schließt die Lücke: „Kaffee“ rückt auf den Platz von „Milch“.
  • size() ist die Zahl der Elemente gerade jetzt. Es ist nicht length, weil eine Liste kein Array ist.
  • println gibt die ganze Liste in eckigen Klammern aus.

So sieht es in ArrayList aus. Die Zahl in den Klammern ist die Anfangsgröße des Arrays. Ohne sie ist es 10. Hier ist es 3, damit du siehst, was passiert, wenn das Array voll wird:

ArrayList<String> cart = new ArrayList<>(3);
cart.add("Brot");
cart.add("Milch");
cart.add("Kaffee");
cart.add("Butter");
cart.remove("Milch");
System.out.println(cart);
System.out.println("Artikel: " + cart.size());
Schritt für Schritt, in Worten
  1. cart zeigt auf ein ArrayList-Objekt. Darin liegen ein Array mit 3 Plätzen und ein Zähler size.
  2. add legt jedes Element auf den ersten freien Platz und erhöht size.
  3. Das Array ist voll. ArrayList legt ein neues mit 4 Plätzen an und kopiert die drei Elemente hinein.
  4. Das Objekt zeigt jetzt auf das neue Array, das alte braucht niemand mehr. „Butter“ kommt auf den freien Platz.
  5. remove entfernt „Milch“, und alles danach rückt einen Platz nach links. Es bleibt keine Lücke.
  6. Von außen siehst du nur eine Liste mit drei Artikeln: Das Kopieren und Verschieben erledigt ArrayList.

Die Idee

Was in die spitzen Klammern gehört

ArrayList<String> bedeutet „eine Liste mit Text“. Der Typ in den spitzen Klammern heißt Typparameter (Generics). Er sagt dem Compiler, was in der Liste ist, und der Compiler setzt es durch:

Main.java
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<String> cart = new ArrayList<>();
cart.add("Brot");
cart.add(5);
}
}
Kompilierfehler
Main.java:7: error: incompatible types: int cannot be converted to String
cart.add(5);
^

Darum gibt cart.get(0) direkt einen String zurück, ohne Umwandlung.

Rechts sind die spitzen Klammern leer: new ArrayList<>(). Der Compiler nimmt den Typ von der linken Seite.

Meist wird die Variable mit dem Interface List deklariert, und die Klasse ArrayList steht nur nach new:

List<String> cart = new ArrayList<>();
cart.add("Brot");
System.out.println(cart.get(0));

Das ist die Polymorphie aus dem Modul „Vererbung und Polymorphie“: List sagt, was eine Liste kann, und ArrayList ist eine Art, es zu tun. Du brauchst zwei imports: java.util.ArrayList und java.util.List. Ab hier zeigt die Lektion sie nicht mehr.

Die Idee

Indizes: get, set, add, indexOf

Eine Liste hat Indizes wie ein Array, von 0 bis size() - 1. Aber statt [ ] nimmst du Methoden:

List<String> tasks = new ArrayList<>();
tasks.add("Rechnung März");
tasks.add("Bank anrufen");
tasks.add("Lagerbericht");
System.out.println(tasks.get(0));
tasks.set(1, "Termin bei der Bank");
tasks.add(0, "Kaffee mit dem Team");
System.out.println(tasks);
System.out.println(tasks.indexOf("Lagerbericht"));
System.out.println(tasks.contains("Bank anrufen"));
Ausgabe
Rechnung März
[Kaffee mit dem Team, Rechnung März, Termin bei der Bank, Lagerbericht]
3
false
  • get(i) liest, und set(i, x) ersetzt.
  • add(i, x) fügt bei Index i ein und schiebt den Rest nach rechts.
  • indexOf(x) sucht und gibt den Index oder -1 zurück, und contains(x) sagt nur, ob es darin ist.
Genauer, für Neugierige
  • Ein Index außerhalb der Liste bricht das Programm ab, wie bei einem Array:
tasks.get(3) bei 3 Aufgaben
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 3 out of bounds for length 3
  • contains und indexOf vergleichen mit equals, nicht mit ==. Darum finden sie gleichen Text, nicht nur dasselbe Objekt.
  • Einfügen und Entfernen vorne sind in einer großen Liste langsam: Jedes Element nach dem Index rückt einen Platz weiter. Bei einer Million Elementen sind das eine Million Verschiebungen.

Probier es aus

Wer ist dran?

Die Liste der Patienten, die beim Arzt warten. Jonas geht hinein, und Anna hat einen Termin, darum bekommt sie den zweiten Platz.

Was gibt das Programm aus?

List<String> waiting = new ArrayList<>();
waiting.add("Jonas");
waiting.add("Maria");
waiting.add("Peter");
waiting.remove(0);
waiting.add(1, "Anna");
System.out.println(waiting + " " + waiting.size());
Antwort

Die Idee

Die Elemente durchlaufen

Eine Liste durchläufst du wie ein Array: mit for-each, wenn du nur die Elemente brauchst, oder mit einem Index, wenn du auch die Nummer brauchst:

List<String> cart = new ArrayList<>();
cart.add("Brot");
cart.add("Kaffee");
cart.add("Butter");
for (String item : cart) {
System.out.println("- " + item);
}
for (int i = 0; i < cart.size(); i++) {
System.out.println((i + 1) + ". " + cart.get(i));
}
Ausgabe
- Brot
- Kaffee
- Butter
1. Brot
2. Kaffee
3. Butter
Genauer, für Neugierige
  • Entferne keine Elemente aus einer Liste, während du sie mit for-each durchläufst. Das Programm bricht ab:
for (String item : cart) {
if (item.equals("Brot")) {
cart.remove(item);
}
}
Fehler
Exception in thread "main" java.util.ConcurrentModificationException

Die Exception kommt nicht immer. Entfernst du das vorletzte Element, endet die Schleife zu früh, und das letzte wird nie geprüft. Verlass dich also nicht darauf.

  • Wenn du entfernen musst, durchläufst du mit einem Index von hinten nach vorne. So verschiebt das Entfernen nicht die Elemente, die du noch nicht geprüft hast:
List<String> cart = new ArrayList<>();
cart.add("Brot");
cart.add("Milch");
cart.add("Brot");
for (int i = cart.size() - 1; i >= 0; i--) {
if (cart.get(i).equals("Brot")) {
cart.remove(i);
}
}
System.out.println(cart);
Ausgabe
[Milch]
Im Modul „Modernes Java“ siehst du einen kürzeren Weg: removeIf.

Die Idee

Zahlen in einer Liste: Integer

Eine Liste mit Noten sieht so aus, lässt sich aber nicht kompilieren:

ArrayList<int> scores = new ArrayList<>();
Kompilierfehler
Main.java:5: error: unexpected type
ArrayList<int> scores = new ArrayList<>();
^
required: reference
found: int

In die spitzen Klammern gehört eine Klasse, und int ist keine Klasse. Darum hat jeder primitive Typ eine Hüllklasse: Integer für int, Double für double, Boolean für boolean, Character für char.

List<Integer> scores = new ArrayList<>();
scores.add(85);
scores.add(64);
scores.add(91);
int total = 0;
for (int score : scores) {
total += score;
}
System.out.println("Durchschnitt: " + (double) total / scores.size());
Ausgabe
Durchschnitt: 80.0

scores.add(85) bekommt ein int, aber die Liste will ein Integer. Java packt es von selbst in eine Hülle. Das heißt Autoboxing. In der Schleife ist int score das Gegenteil: Unboxing. Fast immer merkst du den Unterschied nicht.

Genauer, für Neugierige
  • Vergleiche Integer-Werte mit equals, nicht mit ==. == prüft, ob die beiden Variablen auf dasselbe Objekt zeigen:
Integer a = 127, b = 127;
Integer c = 128, d = 128;
System.out.println(a == b);
System.out.println(c == d);
System.out.println(c.equals(d));
Ausgabe
true
false
true

Java hält fertige Objekte für die Zahlen von -128 bis 127 bereit, darum zeigen bei 127 beide Pfeile auf ein Objekt. Bei 128 sind es zwei Objekte.

  • Ein Integer kann null sein, ein int nicht. Packst du null aus, bricht das Programm mit NullPointerException ab. Das begegnet dir in der Lektion über HashMap.

Probier es aus

Finde den Fehler

Ein Theater hält die belegten Plätze in einer Liste. Ein Kunde gibt Platz 2 zurück, und das Programm soll [12, 7, 5] ausgeben. Stattdessen gibt es [12, 2, 5] aus. In welcher Zeile steckt der Fehler?

Wähle die Zeile mit dem Fehler.

Die Idee

Sortieren und eine fertige Liste

Collections.sort sortiert die Liste an Ort und Stelle: Text alphabetisch, Zahlen nach Größe. Die Klasse Collections liegt auch in java.util.

List<String> cities = new ArrayList<>();
cities.add("Hamburg");
cities.add("Berlin");
cities.add("Dresden");
Collections.sort(cities);
System.out.println(cities);
List<Integer> prices = new ArrayList<>(List.of(30, 5, 12));
Collections.sort(prices);
System.out.println(prices);
Ausgabe
[Berlin, Dresden, Hamburg]
[5, 12, 30]

List.of(30, 5, 12) erzeugt eine fertige Liste aus den Werten, die du aufzählst. Aber sie ist unveränderlich: Du kannst darin nichts hinzufügen, entfernen oder sortieren.

List<String> days = List.of("Mo", "Di", "Mi");
days.add("Do");
Fehler
Exception in thread "main" java.lang.UnsupportedOperationException

Darum werden die Preise oben in eine neue ArrayList kopiert: new ArrayList<>(List.of(30, 5, 12)) ist eine Liste, die du ändern kannst.

Genauer, für Neugierige
  • Text wird nach den Codes seiner Zeichen sortiert. Großbuchstaben kommen vor Kleinbuchstaben, darum kommt „Traube“ vor „apfel“:
List<String> fruit = new ArrayList<>(List.of("apfel", "Birne", "banane", "Traube"));
Collections.sort(fruit);
System.out.println(fruit);
Ausgabe
[Birne, Traube, apfel, banane]
  • Wie du eigene Objekte sortierst, zum Beispiel Produkte nach Preis, siehst du in der Lektion „Klassen in Klassen“.

Übung

Listen in Klassen

Löse die Aufgaben in deinem Editor. Die Liste ist ein private-Feld der Klasse, und main ruft nur ihre Methoden auf.

1. Ein Bücherregal. Eine Klasse BookShelf mit einer Methode addBook(String title), die das Buch ans Ende stellt, und takeBook(), die das erste Buch zurückgibt und entfernt (oder null, wenn das Regal leer ist). Füge count() und toString() hinzu. Füge in main „Unter dem Joch“, „Tabak“ und „Der eiserne Leuchter“ hinzu, nimm ein Buch und gib den Rest aus.

Ausgabe
Genommen: Unter dem Joch
2 übrig: [Tabak, Der eiserne Leuchter]

2. Ein Ereignisprotokoll. Eine Klasse Event mit einem Datum und einer Beschreibung und eine Klasse EventLog mit den Methoden addEvent(String date, String description) und getEventsBetween(String from, String to), die eine Liste der Ereignisse zwischen den beiden Daten zurückgibt, einschließlich. Die Daten sind Text in der Form 2026-03-31. In dieser Form sortiert sich der Text genauso wie die Daten, darum vergleicht compareTo aus der Lektion über Text sie richtig. Füge vier Ereignisse hinzu: 2026-01-15 „Jahresinventur“, 2026-03-31 „Bericht erstes Quartal“, 2026-05-20 „Neuer Kaffeelieferant“, 2026-09-01 „Neues Schuljahr“. Gib die vom 2026-03-01 bis 2026-06-30 aus.

Ausgabe
2026-03-31 Bericht erstes Quartal
2026-05-20 Neuer Kaffeelieferant

3. Ein Notizbuch. Eine Klasse Note mit einem Titel und einem Inhalt und eine Klasse Notebook mit den Methoden addNote, findNote(String title) (gibt die Notiz oder null zurück), deleteNote(String title) (gibt true zurück, wenn es etwas gelöscht hat) und count(). Füge die Notizen „OOP“, „Collections“ und „SQL“ hinzu, finde „Collections“, lösche „OOP“ und prüfe, dass sie weg ist.

Ausgabe
Collections: ArrayList wächst von selbst
Gelöscht: OOP
Notizen: 2
Es gibt keine Notiz OOP.

4. Kopfrechnen. Eine Klasse Question mit einem Text und der richtigen Antwort und eine Klasse MathGame mit einer Liste von Fragen, einer Methode addQuestion und einer Methode start(Scanner in). start stellt die Fragen nacheinander, liest die Antwort und sagt am Ende, wie viele richtig waren. Die Fragen sind 2 + 2, 3 * 4 und 15 - 9.

Eingabe
4
12
7
Ausgabe
2 + 2 = Richtig!
3 * 4 = Richtig!
15 - 9 = Falsch, die Antwort ist 6.
Ergebnis: 2 von 3

Weitere Aufgaben

  • Keine Wiederholungen. Lies 6 Namen ein und sammle sie in einer Liste, wobei du die überspringst, die schon darin sind. Für die Eingabe Jonas, Maria, Jonas, Anna, Maria, Peter ist die Ausgabe [Jonas, Maria, Anna, Peter].
  • Der teuerste Artikel. Eine List<Double> enthält Preise. Finde den höchsten und seinen Index, ohne Collections.
  • Die Liste umdrehen. Schreib eine Methode, die eine neue Liste mit denselben Elementen in umgekehrter Reihenfolge zurückgibt. Ändere das Original nicht.
  • Eine Einkaufsliste. Lies die Befehle add milk, remove milk, list und end und halte die Liste zwischen ihnen. Der Befehl, einen Artikel zu entfernen, der nicht darin ist, sagt „Kein solcher Artikel.“

Test

Teste dich

1. Warum ist eine ArrayList für einen Warenkorb praktischer als ein Array?
2. Was sagt <String> in List<String> cart?
3. List<Integer> seats enthält [12, 2, 7, 5]. Was bleibt nach seats.remove(2)?
4. Warum kannst du nicht ArrayList<int> schreiben?
5. List<String> days = List.of("Mo", "Di"); Was passiert bei days.add("Mi")?

Erstellt von Ivo Gergov im Rahmen der Kampagne von Evo Tech für zugängliche Programmierausbildung ·