Einführungsphase

E3 – Grundlagen der Programmierung

Programmieren als Strukturierung von Verarbeitung und Interaktion

Das Themenfeld E3 Grundlagen der Programmierung ist ein zentrales Arbeitsfeld der Einführungsphase. Im Mittelpunkt steht nicht nur das Erlernen einzelner Java-Befehle, sondern der systematische Weg von der Problemstellung zur nachvollziehbaren Lösung.

Die Programmiersprache wird dabei als Mittel zum Zweck genutzt: Sie hilft, Modelle zu präzisieren, Verarbeitungsabläufe zu strukturieren und Ergebnisse zu prüfen. Spätere Themenfelder und Projekte bauen auf diesen Grundlagen auf.

Programmierung wird in E3 als kontrollierte Beschreibung von Abläufen aufgebaut: Anweisungen verändern Zustände, Ausdrücke liefern Werte, Bedingungen steuern Entscheidungen und Wiederholungen. Methoden kapseln solche Verarbeitung so, dass sie benannt, aufgerufen und wiederverwendet werden kann.

Die Kapitel folgen daher einer durchgehenden Lernlinie: Werte und Typen verstehen → Abläufe steuern → Verarbeitung in Methoden kapseln → Datenstrukturen nutzen → EVA/GUI als interaktionsgetriebenes Verarbeitungssystem verstehen → algorithmische Verfahren in Q1.2 vorbereiten.

E3 folgt dabei keinem einzigen Dauerbeispiel, sondern einer wiederkehrenden Denkbewegung: Werte werden gespeichert, Ausdrücke ausgewertet, Bedingungen geprüft, Abläufe gesteuert, Methoden gebildet, Datenstrukturen durchlaufen und Interaktionen über Ereignisse organisiert. Die unterschiedlichen Beispiele zeigen, dass dieselben Programmierideen in verschiedenen Problemstellungen wiederkehren.

Kerncurriculum
Kerncurriculum kompakt
Einordnung und Inhalte des Themenfelds E.3

A) Allgemeine Einordnung

Programmierung gehört in der Einführungsphase zu den zentralen Primärerfahrungen der Informatik. Lernende entwickeln dabei vor allem Modellierungs- und Problemlösekompetenz, indem sie schrittweise von einer Idee zu einer überprüfbaren Umsetzung gelangen.

Java wird als objektorientierte Sprache genutzt, in E3 steht jedoch zunächst die prozedurale Grundarbeit mit Datentypen, Ausdrücken, Kontrollstrukturen und Methoden im Vordergrund.

B) Inhalte des Themenfelds E.3

C) Bedeutung für diese Kursseite

Die Kapitel bilden eine sachlogische Lernfolge: vom Aufbau einfacher Programme über Datentypen und Ausdrücke bis zu Kontrollstrukturen, Methoden, Datenstrukturen, EVA und ersten grafischen Anwendungen.

Die Seite arbeitet deshalb bewusst mit mehreren Beispielkontexten: Rechner, Punktbewertungen, Spielabläufe, Geometrie, Textprüfung, Messwertlisten und GUI-Anwendungen. Der rote Faden liegt nicht im gleichen Gegenstand, sondern in derselben fachlichen Bewegung von Zustand, Auswertung, Entscheidung, Wiederholung, Kapselung, strukturierter Datenarbeit und Interaktion.

Inhalte, Beispiele und Aufgaben sind so angeordnet, dass die fachliche Progression von grundlegenden Programmierschritten bis zu benannten Verarbeitungsroutinen nachvollziehbar bleibt. Konkrete Such- und Sortierverfahren werden erst in Q1.2 systematisch untersucht.

Quelle

Hessisches Ministerium für Kultus, Bildung und Chancen (2024): Kerncurriculum gymnasiale Oberstufe Informatik, Themenfeld E.3. Fachliche Strukturorientierung ergänzt durch das begleitende Java-Skript.

Programmiergrundlagen
Einführung in Java und Aufbau einfacher Programme
Wie Programme geschrieben, übersetzt und als Folge von Anweisungen aufgebaut werden

Die kleinste lauffähige Programmeinheit bildet den Einstieg in die Programmierung. Sie schafft die Grundlage für den späteren Umgang mit Variablen, Datentypen und Berechnungen.

1. Konzeptklärung: Programm, Quelltext und Ausführung

Ein Programm ist eine formal beschriebene Folge ausführbarer Anweisungen zur Lösung eines Problems. In Java wird diese Beschreibung als Quelltext in .java-Dateien notiert. Der Quelltext ist menschenlesbar, aber nicht direkt maschinenausführbar.

2. Strukturelle Einordnung: Übersetzung und Laufzeit

Java-Programme durchlaufen zwei klar getrennte Schritte. Zunächst übersetzt der Compiler den Quelltext in Bytecode (.class), anschließend führt die Java Virtual Machine (JVM) diesen Bytecode aus. Die Trennung von Übersetzung und Ausführung macht nachvollziehbar, warum Übersetzungsfehler und Laufzeitfehler unterschiedliche Ursachen haben.

Quelltext .java-Datei, für Menschen lesbar
Compiler prüft Syntax und übersetzt
Bytecode .class-Datei, Zwischenform
JVM führt den Bytecode zur Laufzeit aus
Ausgabe entsteht erst beim Programmlauf

Der Quelltext beschreibt das Programm für Menschen. Der Compiler prüft und übersetzt ihn. Die JVM führt den erzeugten Bytecode aus. Sichtbare Ausgaben oder Laufzeitfehler entstehen erst, wenn das Programm tatsächlich läuft.

3. Formale Umsetzung: Klasse, main-Methode und Anweisung

Eine ausführbare Java-Anwendung besitzt mindestens eine Klasse mit einer main-Methode als Startpunkt. Die Anweisungen innerhalb von main werden in der notierten Reihenfolge ausgeführt.

Leselogik: Startpunkt statt Dateianfang

Beim Ausführen sucht die JVM die passende main-Methode. Erst dort beginnt der Programmablauf; Klassenrahmen, Importe oder später notierte Hilfsmethoden werden nicht einfach von oben nach unten ausgeführt.

Im E3-Kontext dient die Klasse zunächst vor allem als notwendiger Java-Rahmen für ein lauffähiges Programm. Der systematische Objekt- und Klassenbegriff wird später in Q1.1 ausgearbeitet.

4. Beispiel: Minimales, vollständiges Java-Programm

public class HalloWelt {
    public static void main(String[] args) {
        System.out.println("Hallo Welt");
    }
}
Ausführungskette anzeigen
Schritt Wirkung Fachliche Ebene
1Der Quelltext wird als HalloWelt.java gespeichert.Quelltext
2Der Compiler prüft die Syntax.Übersetzung
3Bei korrektem Code entsteht Bytecode in HalloWelt.class.Zwischenform
4Die JVM sucht die main-Methode als Einstiegspunkt.Ausführung
5println erzeugt die sichtbare Ausgabe.Konsole
Konsolenausgabe und Fehlerfall anzeigen
Konsolenausgabe
Hallo Welt
Fehlerfall

Fehlt das Semikolon nach System.out.println("Hallo Welt"), kann der Compiler die Anweisung nicht abschließen.

';' expected

Deutung: Das Programm steht nicht schon als fertige Ausführung im Quelltext. Erst nach erfolgreicher Übersetzung kann die JVM die main-Methode starten und die Ausgabe erzeugen.

Das Beispiel enthält genau eine Klasse, genau eine Startmethode und genau eine auszuführende Anweisung. Damit ist die grundlegende Programmstruktur vollständig sichtbar, ohne zusätzliche Sprachelemente vorwegzunehmen.

5. Typische Fehlvorstellungen

Häufig wird angenommen, die Datei werde „Zeile für Zeile“ ohne Struktur ausgeführt. Tatsächlich startet die Ausführung an der main-Methode, nicht am Anfang der Datei.

Ebenfalls verbreitet ist die Gleichsetzung von Quelltext und lauffähigem Programm. Der Quelltext muss zuerst erfolgreich übersetzt werden; erst der erzeugte Bytecode ist ausführbar.

Für ein tragfähiges Grundverständnis ist die klare Unterscheidung der Ebenen entscheidend: Konzept (Programm als Anweisungsfolge), formale Syntax (Klasse und main-Signatur) und technischer Prozess (Compiler/JVM). Auf dieser Basis werden Programmzustände anschließend über Variablen und Datentypen explizit und berechenbar gemacht. Syntax beschreibt dabei, wie Java-Code korrekt geschrieben wird; ebenso wichtig ist die Wirkung einer Anweisung, eines Ausdrucks oder einer Kontrollstruktur bei der Ausführung. Diese Brücke von Schreibform zu Wirkung bereitet spätere Theorieperspektiven vor, ohne sie in E3 auszubreiten.

Datentypen und Variablen
Variablen, Zuweisungen und Datentypen
Werte speichern, verändern und passend typisieren

Nach der Programmgrundstruktur rückt der Inhalt einzelner Anweisungen in den Mittelpunkt: Werte speichern, verändern und mit passenden Typen absichern.

1. Konzeptklärung: Variable als benannter Speicherort

Eine Variable bezeichnet einen Speicherbereich, dem ein Name zugeordnet ist. Der Name ermöglicht den Zugriff auf den aktuell gespeicherten Wert im Programmablauf.

2. Strukturelle Einordnung: Zustand im Programm

Variablen machen Programmzustände explizit. Während ein Programm ausgeführt wird, werden Werte gelesen, berechnet und erneut gespeichert. Dadurch lassen sich Zwischenergebnisse nachvollziehbar darstellen und weiterverarbeiten.

3. Formale Umsetzung: Deklaration, Initialisierung und Zuweisung

Die Deklaration legt Datentyp und Namen fest. Eine Initialisierung weist beim Anlegen bereits einen Startwert zu. Eine spätere Zuweisung ersetzt den bisherigen Wert der Variablen.

public class VariablenDemo {
    public static void main(String[] args) {
        int kontoStand = 100;      // Deklaration + Initialisierung
        kontoStand = kontoStand + 25; // Zuweisung: Zustand ändert sich

        double temperatur = 21.5;
        boolean istVoll = false;
        char note = 'A';

        System.out.println(kontoStand);
    }
}

Bei einer Zuweisung wird zuerst die rechte Seite ausgewertet. Erst danach wird das Ergebnis links gespeichert. Deshalb ist kontoStand = kontoStand + 25; sinnvoll, obwohl es keine mathematische Gleichung ist.

Trace / Laufspur anzeigen
Schritt Auswertung Wert von kontoStand
Initialisierung 100 wird gespeichert 100
rechte Seite kontoStand + 25 wird zu 125 ausgewertet 100
Zuweisung Das Ergebnis wird links gespeichert 125
Ausgabe System.out.println(...) liest den aktuellen Wert 125
Startzustand und Konsolenausgabe anzeigen
Startzustand

Vor der ersten Anweisung ist kontoStand noch nicht angelegt. Nach der Initialisierung speichert die Variable 100.

Konsolenausgabe
125

Deutung: Bei einer Zuweisung wird zuerst rechts ausgewertet. Erst danach verändert sich der gespeicherte Wert links.

Dieselbe Zustandslogik steckt im Taschenrechnerkontext: Eingabewerte werden gespeichert, ein Rechenausdruck wird ausgewertet und das Ergebnis ersetzt oder ergänzt einen bisherigen Zustand.

4. Datentypen in Java: Übersicht der primitiven Typen

Die folgenden acht primitiven Datentypen sind fest in Java definiert. Sie speichern einfache Werte direkt und besitzen feste Größen und Wertebereiche.

Datentyp Größe Wertebereich Standardwert
booleanJVM-abhängig (logisch 1 Bit)true, falsefalse
char16 BitU+0000 bis U+FFFF'\u0000'
byte8 Bit-128 bis 1270
short16 Bit-32.768 bis 32.7670
int32 Bit-2.147.483.648 bis 2.147.483.6470
long64 Bit-9.223.372.036.854.775.808 bis 9.223.372.036.854.775.8070L
float32 Bitca. ±1,4E-45 bis ±3,4E+380.0f
double64 Bitca. ±4,9E-324 bis ±1,7E+3080.0d

5. Primitive Datentypen und Objekte sauber unterscheiden

Primitive Typen speichern unmittelbare Einzelwerte (z. B. Zahl, Zeichen, Wahrheitswert). Bei Referenztypen verweist eine Variable dagegen auf ein Objekt, das intern mehrere Daten und ggf. Methodenbezug zusammenfasst.

int punkte = 42;                  // primitiver Wert liegt direkt vor
int[] messwerte = {3, 5, 8};      // Variable speichert Referenz auf ein Array-Objekt
String name = "Lea";              // Referenz auf ein String-Objekt

Diese Unterscheidung ist für spätere Kapitel zentral: Arrays und andere Datenstrukturen arbeiten mit Referenzen auf Objekte, während numerische Berechnungen häufig auf primitiven Typen stattfinden.

6. Typumwandlung

Bei der Typumwandlung wird ein Wert in einen anderen Datentyp überführt. Java unterscheidet automatische (implizite) Umwandlung und explizites Casting.

Numerische Typen: von kleiner zu größer byte short int long float double meist implizit möglich (Widening) Rückrichtung: explizites Casting nötig, ggf. Informationsverlust
Von links nach rechts ist die Umwandlung typischerweise automatisch möglich; in Gegenrichtung nur mit explizitem Casting und möglichem Genauigkeits- oder Werteverlust.
Automatische (implizite) Umwandlung
int anzahl = 7;
double alsDouble = anzahl; // int -> double
float alsFloat = anzahl;   // int -> float
Arithmetische Beförderung bei kleinen Ganzzahltypen
byte a = 10;
short b = 20;
int summe = a + b; // byte/short werden in Ausdrücken zu int
Explizite Umwandlung (Casting)
double preis = 19.99;
int euro = (int) preis;   // 19, Nachkommastellen fallen weg

long gross = 4_000_000_000L;
int klein = (int) gross;  // Überlauf möglich

float note = 2.7f;
int ganzzahl = (int) note; // 2

7. Typische Fehlvorstellungen

Der Operator = wird oft als mathematische Gleichheit interpretiert. In Java bedeutet er Zuweisung: Der rechte Ausdruck wird ausgewertet und sein Ergebnis links gespeichert.

Ebenso verbreitet ist die Annahme, der Datentyp sei nur „Beschriftung“. Tatsächlich bestimmt der Typ, welche Werte zulässig sind, wie sie gespeichert werden und ob eine Umwandlung automatisch oder nur per Casting möglich ist.

Variablenarbeit, Typsystem und Typumwandlung greifen direkt ineinander. Diese Grundlage ermöglicht es, in den folgenden Kapiteln Ausdrücke und Bedingungen zu formulieren und daraus eine präzise Ablaufsteuerung über Kontrollstrukturen abzuleiten.

Operatoren und Bedingungen
Operatoren und logische Ausdrücke
Rechnen, vergleichen und Bedingungen formulieren

Variablen und Datentypen liefern die Wertebasis. Operatoren verknüpfen diese Werte zu Berechnungen, Vergleichen und Bedingungen.

1. Konzeptklärung: Ausdruck als auswertbare Struktur

Ein Ausdruck kombiniert Werte, Variablen, Konstanten und Operatoren zu einer auswertbaren Einheit. Das Ergebnis eines Ausdrucks hat einen Datentyp, zum Beispiel numerisch oder boolesch. Operatoren sind damit nicht nur Rechenzeichen, sondern zentrale Bausteine zur Formulierung von Berechnungen und Bedingungen.

2. Strukturelle Einordnung: Ausdrücke im Programmablauf

Arithmetische Ausdrücke erzeugen numerische Ergebnisse, Vergleichsausdrücke erzeugen Wahrheitswerte, und logische Ausdrücke verknüpfen Wahrheitswerte zu komplexeren Bedingungen. Damit bilden sie die fachliche Brücke zwischen Datenverarbeitung und Ablaufsteuerung.

3. Formale Umsetzung: Operatorgruppen, Priorität und Klammerung

Typische arithmetische Operatoren sind +, -, *, / und %. Vergleichsoperatoren sind unter anderem ==, !=, <, <=, >, >=. Logische Operatoren wie &&, || und ! arbeiten auf booleschen Werten. Klammern steuern die Auswertungsreihenfolge explizit und reduzieren Mehrdeutigkeiten.

public class OperatorenDemo {
    public static void main(String[] args) {
        int a = 8;
        int b = 3;

        int summe = a + b * 2;                 // arithmetischer Ausdruck
        boolean istGleich = (a == b);          // Vergleichsausdruck
        boolean istGueltig = (a > b) && (b > 0); // logischer Ausdruck

        System.out.println(summe);
        System.out.println(istGleich);
        System.out.println(istGueltig);
    }
}

4. Beispielanalyse: numerisches vs. boolesches Ergebnis

a + b * 2 liefert einen numerischen Wert. a == b liefert den Wahrheitswert true oder false. (a > b) && (b > 0) verknüpft zwei boolesche Teilausdrücke zu einer Gesamtbedingung, die später in if- oder while-Strukturen verwendet werden kann.

Auswertungsschritt Teilausdruck Ergebnis Typ
1 a > b mit a = 8, b = 3 true boolean
2 b > 0 mit b = 3 true boolean
3 true && true true boolean
Vorbereitete Fallvarianten anzeigen
Fall a b a > b b > 0 Gesamt
A83truetruetrue
B23falsetruefalse
C8-1truefalsefalse
Beispielausgabe des Programms anzeigen
14
false
true

Deutung: Der boolesche Ausdruck entscheidet noch keinen Programmzweig. Er liefert den Wahrheitswert, den if oder while anschließend zur Steuerung des Ablaufs verwendet.

Ausdrücke sind auswertbare Strukturen: Manche liefern Zahlen, andere Wahrheitswerte. Ein Taschenrechnerprogramm nutzt beides zugleich, etwa wenn ein Rechenzeichen geprüft, eine Division durch Null verhindert oder ein zulässiger Wertebereich abgesichert wird.

5. Logische Operatoren in Bedingungen

Sobald Bedingungen aus mehreren Teilaussagen bestehen, werden logische Operatoren zur Verknüpfung benötigt. Sie entscheiden, ob eine Gesamtbedingung in Kontrollstrukturen wie if, while oder for als true oder false ausgewertet wird.

Name Java-Notation Java-Beispiel
Logical and&&(sum > min) && (sum < max)
Logical or||(answer == 'y') || (answer == 'Y')
Logical not!!(number < 0)

Die Tabelle zeigt die typische Rollenverteilung: && fordert, dass beide Teilbedingungen gelten, || akzeptiert mindestens eine zutreffende Bedingung, und ! negiert einen vorhandenen Wahrheitswert.

6. Wahrheitstabelle für &&, || und !

Wahrheitstabellen helfen dabei, das Verhalten logischer Operatoren exakt zu überprüfen. Gerade bei verschachtelten Bedingungen in Schleifen und Verzweigungen lässt sich so vorab prüfen, welche Kombinationen zu einer Ausführung des jeweiligen Blocks führen.

A B A && B A || B !(A)
truetruetruetruefalse
truefalsefalsetruefalse
falsetruefalsetruetrue
falsefalsefalsefalsetrue

Für die Praxis heißt das: Bedingungen lassen sich aus mehreren Teilaussagen zusammensetzen, um Programmabläufe präzise zu steuern. Das ist zentral für Grenzprüfungen in if-Anweisungen, Abbruchkriterien in while-Schleifen und kombinierte Laufbedingungen in for-Schleifen.

7. Typische Fehlvorstellungen

Ein häufiger Fehler ist die Verwechslung von = (Zuweisung) und == (Vergleich). Dadurch wird statt einer Bedingung unbeabsichtigt ein Wert zugewiesen oder ein Syntaxfehler erzeugt.

Ebenso wird oft angenommen, jeder Ausdruck liefere eine Zahl. Vergleichs- und logische Ausdrücke liefern jedoch boolesche Werte und sind damit direkt als Bedingungen interpretierbar.

Ohne Klammerung wird die Priorität von Operatoren häufig falsch eingeschätzt. Explizite Klammern sichern die beabsichtigte Auswertungsreihenfolge.

Die klare Trennung zwischen Berechnung, Vergleich und logischer Verknüpfung macht sichtbar, wie Ausdrücke als Grundlage für Verzweigungen und Schleifen dienen und damit die Ablaufsteuerung ermöglichen.

Kontrollstrukturen
Kontrollstrukturen
Abläufe steuern und mit Struktogrammen systematisch modellieren

Logische Ausdrücke führen direkt zur Steuerung vollständiger Abläufe: aus einzelnen Bedingungen entstehen geordnete Folgen von Anweisungen, Entscheidungen und Wiederholungen.

A) Einführung: Was sind Kontrollstrukturen?

Kontrollstrukturen ordnen einzelne Anweisungen zu nachvollziehbaren Abläufen. Sie legen fest, ob Anweisungen nacheinander ausgeführt werden (Sequenz), ob zwischen Alternativen entschieden wird (Verzweigung) oder ob Schritte wiederholt werden (Schleife). Bedingungen werden dabei in Verzweigungen und Schleifen ausgewertet: Ihr Wahrheitswert entscheidet, welcher Zweig läuft oder ob eine Wiederholung fortgesetzt wird. Damit entsteht zunächst kontrollierte Ablaufmodellierung, noch keine formale Algorithmusanalyse.

B) Struktogramm-Notation (grundlegend)

Struktogramme beschreiben Ablauflogik in Blöcken. Die Notation ist sprachneutral und passt direkt zum eingebundenen Struktogramm-Tool: Sequenz als Folge von Blöcken, Verzweigung als geteilte Entscheidung, Schleifen als wiederholte Blöcke mit Bedingung. Dadurch wird sichtbar, aus welchen elementaren Formen spätere algorithmische Verfahren aufgebaut werden können.

Struktogramm: Grundnotation

1) Bedingte Anweisung (if / if-else)

Erklärung: Eine Bedingung steuert, welcher Pfad ausgeführt wird. Bei if-else sind zwei Pfade explizit vorhanden.

if (temperatur < 0) {
    status = "Frost";
} else {
    status = "kein Frost";
}
Struktogramm-Konvention: Verzweigung

Leselogik: Was passiert hier? Es wird genau ein Zweig ausgeführt. Wie liest man das Struktogramm? Erst Bedingung prüfen, dann den passenden Pfad verfolgen.

2) While-Schleife

Erklärung: Die while-Schleife ist kopfgesteuert. Die Bedingung wird vor jedem Durchlauf geprüft.

int i = 0;
while (i < 3) {
    System.out.println(i);
    i++;
}
Struktogramm-Konvention: kopfgesteuerte Schleife

Leselogik: Was passiert hier? Der Block läuft wiederholt, solange die Bedingung wahr bleibt. Wie liest man das Struktogramm? Bedingung oben, dann Schleifenkörper, danach Rücksprung zur Bedingung.

Trace / Laufspur anzeigen
Durchlauf i vor Prüfung Bedingung i < 3 Ausgabe i danach
10true01
21true12
32true23
43falsekeine3
Konsolenausgabe anzeigen
0
1
2

Deutung: Die Schleife wiederholt nicht blind. Vor jedem Durchlauf wird ein aktueller Zustand geprüft. Erst wenn die Bedingung false wird, endet der Ablauf.

3) For-Schleife

Erklärung: Die for-Schleife bündelt Initialisierung, Bedingung und Schrittweite. Sie ist die typische Zählschleife und bereitet die Iteration über Arrays vor.

int[] werte = {7, 4, 9};
for (int i = 0; i < werte.length; i++) {
    System.out.println(werte[i]);
}
Struktogramm-Konvention: Zählschleife

Leselogik: Was passiert hier? Jeder Index wird genau einmal besucht. Wie liest man das Struktogramm? Ein Zählbereich steuert die Wiederholung, der Körper verarbeitet pro Durchlauf ein Element.

Ablaufproblem Passende Struktur Beispielkontext
Wiederholen, bis ein Ziel erreicht oder aufgegeben wird while Zahlenratespiel
Eingabe wiederholen, bis sie gültig ist while oder do-while gültige Zahl, gültiges Rechenzeichen
Feste Anzahl von Aufgaben bearbeiten for Mathe-Challenge mit zehn Aufgaben
Solange weiterspielen, wie Antworten richtig sind while Endless-Mode

4) Do-While-Schleife

Erklärung: Die do-while-Schleife ist fußgesteuert. Der Schleifenkörper wird mindestens einmal ausgeführt.

int versuche = 0;
do {
    versuche++;
} while (versuche < 1);
Struktogramm-Konvention: fußgesteuerte Schleife

Leselogik: Was passiert hier? Ein erster Durchlauf ist garantiert, erst dann wird geprüft. Wie liest man das Struktogramm? Zuerst den Block, dann die Bedingung als Fortsetzungsentscheidung.

5) Switch-Anweisung

Erklärung: switch modelliert eine Mehrfachverzweigung und ersetzt lange Ketten verschachtelter if-Abfragen.

switch (note) {
    case 1: text = "sehr gut"; break;
    case 2: text = "gut"; break;
    default: text = "weitere";
}
Struktogramm-Konvention: Mehrfachverzweigung

Leselogik: Was passiert hier? Genau ein passender Fall wird gewählt, sonst der Default-Pfad. Wie liest man das Struktogramm? Von der Auswahlbedingung zu genau einem der Alternativpfade.

Brücke zur strukturierten Verarbeitung

Sequenz, Verzweigung und Schleife sind die elementaren Formen, aus denen verlässliche Verarbeitungsabläufe entstehen. Struktogramme machen diese Abläufe unabhängig von einer konkreten Programmiersprache sichtbar. Darauf aufbauend werden Kontrollstrukturen im nächsten Kapitel als wiederverwendbare Teilabläufe in Methoden gekapselt.

EVA-Prinzip
EVA-Prinzip als Grundmodell für Programme
Bereits erarbeitete Bausteine als Eingabe, Verarbeitung und Ausgabe zusammenlesen

Nach Einführung, Datentypen, Operatoren und Kontrollstrukturen ordnet das EVA-Prinzip die bekannten Bausteine zu einem gemeinsamen Funktionsmodell. EVA ist hier kein Neueinstieg, sondern eine rückblickende Strukturformel für vollständige Programmabläufe: Eingaben werden gelesen, Verarbeitung wird gekapselt und Ausgaben werden sichtbar gemacht.

1. Ordnungsmodell: Bekannte Sprachelemente funktional bündeln

  • Eingabe: Daten über Konsole, GUI-Elemente oder andere Quellen erfassen.
  • Verarbeitung: Werte mit Variablen und Datentypen speichern, mit Operatoren berechnen und über Bedingungen, Kontrollstrukturen und Methoden auswerten.
  • Ausgabe: Ergebnisse strukturiert darstellen, weitergeben oder in der Oberfläche zurückmelden.

Die folgende Übersicht zeigt, wie dieses Ordnungsmodell in verschiedenen Programmkontexten sichtbar wird.

Kontext Eingabe Verarbeitung Ausgabe
Konsolenprogramm Scanner liest Werte Methode berechnet oder prüft println zeigt Ergebnis
GUI-Programm TextField und Button Event-Handler ruft Methode auf Label zeigt Ergebnis
Datenprogramm Array mit Messwerten oder Noten Schleife/Methode bildet Statistik Durchschnitt, Minimum, Maximum

Dadurch werden einzelne Kenntnisse nicht isoliert gelesen, sondern als zusammenhängender Ablauf: von der Datenerfassung über eine Methode oder Folge von Methoden bis zur begründeten Ausgabe. Die Verarbeitung ist der Ort, an dem später algorithmische Verfahren stehen können; in E3 wird sie zunächst als klar benannte Verarbeitungsroutine aufgebaut.

EVA ist also nicht an die Konsole gebunden. In Konsolenprogrammen liest Scanner Eingaben, in GUI-Programmen liefern Komponenten Eingabezustände, und in Datenprogrammen kann ein Array die Eingabebasis bilden. Die Verarbeitung sollte in allen Fällen als eigene, prüfbare Methode lesbar bleiben.

Beispiel: Sequenzdiagramm / GUI-Ereignisfolge

Auch in grafischen Oberflächen bleibt die EVA-Logik erhalten: Ein Ereignis löst Verarbeitung aus, die anschließend in einer sichtbaren Ausgabe endet.

Sequenzdiagramm eines GUI-Ereignisses im EVA-Prinzip von Nutzereingabe bis UI-Ausgabe
Beispiel: Namen einlesen und begrüßen
import java.util.Scanner;

public class EvaBegruessung {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Wie heißt du? ");
        String name = scanner.nextLine();
        String gruss = "Hallo, " + name + "!";

        System.out.println(gruss);
    }
}
  • Eingabe: scanner.nextLine() liest den Namen ein.
  • Verarbeitung: Der Begrüßungstext wird mit String-Verkettung aufgebaut.
  • Ausgabe: System.out.println(...) gibt den Text aus.
Beispiel: Zwei Zahlen einlesen und addieren
import java.util.Scanner;

public class EvaAddition {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Erste Zahl: ");
        double a = scanner.nextDouble();
        System.out.print("Zweite Zahl: ");
        double b = scanner.nextDouble();

        double summe = a + b;
        System.out.println("Summe: " + summe);
    }
}
  • Eingabe: Zwei Zahlen werden als double eingelesen.
  • Verarbeitung: Der Operator + berechnet die Summe.
  • Ausgabe: Das Ergebnis wird formatiert ausgegeben.
Beispiel: Alter abfragen und mit if auswerten
import java.util.Scanner;

public class EvaAlter {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Wie alt bist du? ");
        int alter = scanner.nextInt();

        String meldung;
        if (alter >= 18) {
            meldung = "Du bist volljährig.";
        } else {
            meldung = "Du bist minderjährig.";
        }

        System.out.println(meldung);
    }
}
  • Eingabe: Das Alter wird als Ganzzahl eingelesen.
  • Verarbeitung: Eine if-Kontrollstruktur entscheidet zwischen zwei Meldungen.
  • Ausgabe: Die passende Meldung wird ausgegeben.
Beispiel: Punktzahl mit Methode bewerten
import java.util.Scanner;

public class EvaBewertung {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Punktzahl: ");
        int punkte = scanner.nextInt();

        String urteil = bewertePunktzahl(punkte);
        System.out.println("Bewertung: " + urteil);
    }

    public static String bewertePunktzahl(int punkte) {
        if (punkte >= 90) {
            return "sehr gut";
        } else if (punkte >= 75) {
            return "gut";
        }
        return "ausreichend";
    }
}
  • Eingabe: Die Punktzahl wird eingelesen.
  • Verarbeitung: Die Methode bewertePunktzahl(...) kapselt die Entscheidungslogik und liefert ein Ergebnis zurück.
  • Ausgabe: Das zurückgegebene Urteil wird ausgegeben.

2. Fachliche Brücke

Im nächsten Schritt wird die Verarbeitung systematisch in Methoden gegliedert. So kann dieselbe Fachlogik in einem Konsolenprogramm, in einem Test oder später in einer GUI genutzt werden. In ereignisgesteuerten Programmen koppelt ein Event-Handler Eingabezustände, Verarbeitungsmethode und Ausgabe wieder nach dem EVA-Muster.

Methoden
Methoden, Strukturierung und erste Modellierung
Programme in sinnvoll gegliederte Bausteine zerlegen

Kontrollstrukturen beschreiben den Ablauf, Methoden kapseln zusammengehörige Folgen von Anweisungen zu wiederverwendbaren Teilaufgaben.

1. Was ist eine Methode?

Eine Methode ist ein benannter, wiederverwendbarer Ablaufblock innerhalb einer Klasse. Sie wird nur ausgeführt, wenn sie über einen Methodenaufruf gestartet wird. Damit werden Programme nicht als „ein großer Block“, sondern als geordnete Teilaufgaben aufgebaut. In E3 steht Methode deshalb zunächst für eine benannte Teilaufgabe beziehungsweise eine wiederverwendbare Verarbeitungsroutine. Der volle objektorientierte Methodenbegriff als Verhalten von Objekten wird in Q1.1 systematisch entwickelt.

2. Warum nutzt man Methoden?

Methoden verbessern Lesbarkeit, Wartbarkeit und Wiederverwendbarkeit. Wenn dieselbe Logik mehrfach gebraucht wird, wird sie einmal definiert und anschließend an mehreren Stellen aufgerufen. So entsteht die erste konkrete Form, in der ein Verfahren benannt, abgegrenzt und wiederverwendet wird. Das bereitet den Algorithmusgedanken vor, ohne hier bereits Such- und Sortieralgorithmen zu analysieren.

3. Aufbau einer Methode: Methodenkopf und Methodenrumpf

Eine Methodendeklaration besteht aus Methodenkopf und Methodenrumpf. Im Kopf stehen Sichtbarkeit, ggf. static, Rückgabetyp, Name und Parameterliste. Im Rumpf steht die eigentliche Verarbeitung.

public static int berechneRabatt(int preis, int prozent) {
    int rabatt = preis * prozent / 100;
    return rabatt;
}

Leselogik: public static int berechneRabatt(int preis, int prozent) ist der Kopf. Der Block zwischen { und } ist der Rumpf.

Name berechneRabatt
Eingaben int preis, int prozent
Rückgabe int als berechneter Rabatt
Verarbeitung Preis und Prozentsatz werden zu einem Wert verrechnet.

Eine Methode wirkt damit wie eine fachliche Schnittstelle: Außen ist sichtbar, welche Eingaben erwartet werden, wie die Routine heißt und welcher Ergebnistyp zurückkommt. Die konkrete Verarbeitung bleibt im Rumpf gekapselt.

Methodenaufruf simulieren
Aufrufstelle

int r = berechneRabatt(100, 20);

Die Argumente sind 100 und 20.

Endzustand

return gibt 20 zurück.

Die Aufrufstelle speichert danach r = 20.

Phase Wirkung
ArgumenteAn der Aufrufstelle stehen 100 und 20.
ParameterbindungIn der Methode gilt preis = 100, prozent = 20.
Verarbeitung100 * 20 / 100 wird zu 20 ausgewertet.
lokaler Wertrabatt = 20 existiert innerhalb der Methode.
Rückgabereturn rabatt; gibt 20 an die Aufrufstelle zurück.
Nutzungint r speichert den zurückgegebenen Wert.

Deutung: Parameter sind lokale Namen innerhalb der Methode. Der Rückgabewert verlässt die Methode erst durch return und muss an der Aufrufstelle genutzt oder gespeichert werden.

Methodenkontext Typische Schnittstelle Fachliche Funktion
PunktbewertungbewertePunktzahl(int punkte)Grenzwerte prüfen und Urteil zurückgeben
QuaderberechnungberechneVolumen(double a, double b, double c)gleiche Eingaben für unterschiedliche Rückgaben nutzen
GeometrieberechneRaumdiagonale(double a, double b, double c)Formel als benannte Verarbeitung kapseln
AnhaltewegberechneAnhalteweg(double v)Fachlogik später aus GUI oder Konsole aufrufen

4. Methoden aufrufen: Name + Klammern

Eine Methode wird über ihren Namen mit Klammern aufgerufen. Einmal definierte Methoden können mehrfach aufgerufen werden, auch mit unterschiedlichen Eingaben.

public static void main(String[] args) {
    begruessung();
    begruessung();
}

public static void begruessung() {
    System.out.println("Willkommen im Kurs E3.");
}

Die Methode begruessung() besitzt keine Parameter und keinen Rückgabewert. Sie führt beim Aufruf nur eine Aktion aus.

5. Parameter: Eingaben für eine Teilaufgabe

Parameter machen Methoden flexibel. Statt feste Werte im Methodenrumpf zu verwenden, werden die Werte beim Aufruf übergeben.

public static void ausgabeTicketpreis(int preis) {
    System.out.println("Ticketpreis: " + preis + " €");
}

public static void main(String[] args) {
    ausgabeTicketpreis(29);
    ausgabeTicketpreis(45);
}

Die Methode bleibt gleich, nur das Argument ändert sich. So wird dieselbe Logik für verschiedene Situationen genutzt.

6. Rückgabewerte, return und void

Methoden mit Rückgabetyp liefern einen Rückgabewert an die Aufrufstelle zurück. Das Ergebnis wird über return zurückgegeben. Bei void-Methoden steht die Aktion im Vordergrund, nicht ein berechneter Rückgabewert.

// Methode mit Rückgabewert
public static int berechneGesamtpreis(int preisProTicket, int anzahl) {
    return preisProTicket * anzahl;
}

// void-Methode
public static void zeigeHinweis() {
    System.out.println("Bitte Anzahl überprüfen.");
}

public static void main(String[] args) {
    int gesamt = berechneGesamtpreis(40, 3);
    System.out.println("Gesamtpreis: " + gesamt);
    zeigeHinweis();
}

Modellierungsbezug: Berechnungen (z. B. Preise, Zeiten, Indizes) eignen sich oft für Methoden mit Rückgabewert, während Statusmeldungen oder Ausgaben häufig als void-Methoden formuliert werden.

Beispiel: Verarbeitung unabhängig vom Eingabekanal

Die Methode enthält die fachliche Verarbeitung. Sie kann aus main heraus oder später aus einem Event-Handler aufgerufen werden.

public static String bewertePunktzahl(int punkte) {
    if (punkte >= 90) {
        return "sehr gut";
    } else if (punkte >= 75) {
        return "gut";
    }
    return "ausreichend";
}

// Konsolenprogramm:
int konsolenPunkte = 82;
String urteil = bewertePunktzahl(konsolenPunkte);
System.out.println("Bewertung: " + urteil);

// GUI-Event-Handler:
int guiPunkte = Integer.parseInt(eingabe.getText());
ausgabe.setText("Bewertung: " + bewertePunktzahl(guiPunkte));

Die Eingabe kann aus der Konsole oder aus einer GUI-Komponente stammen. Die Verarbeitungsroutine bleibt dieselbe.

7. static im aktuellen E3-Kontext

In E3 werden viele Beispiele innerhalb einer Klasse mit main umgesetzt. Damit main eine Methode direkt aufrufen kann, wird sie in diesem Kontext meist als static notiert. Didaktisch genügt hier: static bedeutet, dass die Methode zur Klasse gehört und ohne erzeugtes Objekt nutzbar ist. Das ist eine Arbeitsregel für den Einstieg, keine vollständige OOP-Erklärung.

8. Methoden als Strukturierungsprinzip

Größere Programme werden in fachlich sinnvolle Teilaufgaben zerlegt: Eingaben prüfen, Werte berechnen, Ergebnisse ausgeben. Dadurch wird der Programmablauf besser lesbar und leichter wartbar. Diese Denkweise verbindet Methoden direkt mit Kontrollstrukturen, Datenstrukturen und dem späteren Algorithmus-Begriff. Auch im Struktogramm kann ein Methodenaufruf als Blockaufruf modelliert werden.

public static boolean istGueltigerIndex(int index, int[] daten) {
    return index >= 0 && index < daten.length;
}

public static int leseWertSicher(int index, int[] daten) {
    if (istGueltigerIndex(index, daten)) {
        return daten[index];
    }
    return -1;
}

Hier ruft eine Methode eine andere auf. Kontrollstruktur (if) und Datenstruktur (int[]) werden sauber in Teilaufgaben gegliedert.

9. Methodenüberladung in tragfähigem Umfang

Bei der Methodenüberladung haben Methoden denselben Namen, aber unterschiedliche Parameterlisten. Der Name beschreibt die fachliche Aufgabe, die Parameterliste die konkrete Variante.

public static int addiere(int a, int b) {
    return a + b;
}

public static double addiere(double a, double b) {
    return a + b;
}

Die Aufrufe addiere(3, 4) und addiere(2.5, 1.5) wählen automatisch die passende Methode. Für E3 reicht dieses Grundverständnis; weiterführende Spezialfälle folgen später.

10. Typische Fehlvorstellungen (kompakt)

Methoden werden nicht automatisch ausgeführt, sondern nur durch Aufruf. Parameter sind lokal und keine globalen Variablen. Ein Rückgabewert entsteht nur bei Methoden mit passendem Rückgabetyp und return. Methodenüberladung unterscheidet sich über die Parameterliste, nicht über den Methodennamen allein.

So strukturierte Teilaufgaben arbeiten in der Praxis häufig auf größeren Datenmengen; dafür sind Arrays und Strings als Datenstrukturen zentral.

Datenstrukturen
Datenstrukturen
Arrays und Strings als strukturierte Grundlage für algorithmisches Arbeiten

Nach der methodischen Strukturierung steht die Datenperspektive im Mittelpunkt: Die gleiche Problemstellung wird nicht mehr mit Einzelwerten, sondern mit geordneten Datensammlungen bearbeitet.

A) Einführung: Warum Datenstrukturen?

Einzelne Variablen reichen nur für einzelne Werte. Sobald mehrere zusammengehörige Informationen verarbeitet werden sollen (z. B. mehrere Messwerte oder ein ganzer Text), braucht man Datenstrukturen. Sie speichern nicht nur mehrere Daten, sondern ordnen sie so, dass gezielter Zugriff, systematisches Durchlaufen und algorithmische Verarbeitung möglich werden.

Damit entsteht die fachliche Entwicklung dieses Kapitels: von einzelnen Variablen hin zu strukturierten Datensammlungen und weiter zur algorithmischen Verarbeitung.

B) Arrays als zentrale Datenstruktur

Ein Array speichert mehrere Werte gleichen Typs unter einem Namen. Die Länge ist nach der Erzeugung fest. Auf einzelne Elemente greift man über den Index zu. Indizes beginnen bei 0; der letzte gültige Index ist immer array.length - 1.

// Initialisierung mit fester Länge und Startwerten
int[] zahlen = {10, 20, 30, 40};

// Zugriff über Index
int ersterWert = zahlen[0];
int dritterWert = zahlen[2];
Index 0 1 2 3
Wert 10 20 30 40

zahlen[0] liefert 10, zahlen[2] liefert 30; zahlen[4] wäre ungültig, weil die vier Werte nur die Indizes 0 bis 3 besitzen.

Der Nutzen von Arrays liegt nicht nur in der Speicherung, sondern vor allem im geordneten Zugriff: Positionen sind eindeutig adressierbar und können deshalb gezielt geprüft, verändert oder verglichen werden.

// Durchlaufen eines Arrays mit for-Schleife
for (int i = 0; i < zahlen.length; i++) {
    System.out.println("Index " + i + " -> " + zahlen[i]);
}
Durchlauf i Bedingung i < zahlen.length Zugriff Ausgabe
10truezahlen[0]10
21truezahlen[1]20
32truezahlen[2]30
43truezahlen[3]40
54falsekein Zugriffkeine

Deutung: Die Schleife besucht jeden gültigen Index genau einmal. Bei Noten-, Punkt- oder Messwertlisten ist diese Laufspur die Grundlage für Durchschnitt, Minimum, Maximum und Zählungen.

Ausblick: Arrays mit java.util.Arrays auswerten

java.util.Arrays ist eine Hilfsklasse mit statischen Methoden zur Arbeit mit Arrays. Dieser Block ist ein optionaler Ausblick; die Methoden sind nützlich, aber nicht Pflichtstoff der aktuellen Unterrichtsphase.

import java.util.Arrays;

int[] zahlen = {40, 10, 30, 20};

System.out.println(Arrays.toString(zahlen));
Arrays.sort(zahlen);
int position = Arrays.binarySearch(zahlen, 30);
  • Arrays.toString(array) erzeugt eine lesbare Ausgabe der Array-Inhalte.
  • Arrays.sort(array) sortiert ein Array.
  • Arrays.binarySearch(array, wert) sucht in einem sortierten Array nach einem Wert.

Wichtig: binarySearch setzt ein sortiertes Array voraus. Wird vorher nicht sortiert, ist das Ergebnis für Lernende fachlich nicht verlässlich interpretierbar.

Das Durchlaufen (Iterieren) über Arrays verbindet dieses Kapitel direkt mit den Kontrollstrukturen aus Kapitel 4.

C) Strings als besondere Datenstruktur für Text

Ein String ist eine Zeichenfolge. Die Java-8-Dokumentation beschreibt String als Klasse für Zeichenketten und nennt Methoden zum Untersuchen einzelner Zeichen, zum Vergleichen, Suchen, Ausschneiden und Umformen von Text.

Auch bei Strings beginnt die Indizierung bei 0. Der letzte gültige Index ist string.length() - 1. Einzelne Zeichen werden mit charAt(index) gelesen. Anders als Arrays sind Strings unveränderlich (immutable).

String kurs = "Informatik";

int laenge = kurs.length();
char erstesZeichen = kurs.charAt(0);
char fuenftesZeichen = kurs.charAt(4);
String anfang = kurs.substring(0, 5); // "Infor"
Index 0 1 2 3 4
Zeichen I n f o r

Bei String kurs = "Informatik"; liefert kurs.charAt(0) das Zeichen I, kurs.charAt(4) das Zeichen r. kurs.length() liefert die Anzahl der Zeichen, nicht den letzten Index.

Ausdruck Deutung Ergebnis
kurs.substring(0, 5) Startindex 0 ist enthalten, Endindex 5 ist ausgeschlossen "Infor"
kurs.indexOf("mat") liefert die erste Fundstelle des Teilstrings 5
kurs.indexOf("@") gesuchtes Zeichen kommt nicht vor -1

Der Rückgabewert -1 ist ein Diagnosefall: Vor einem substring-Zugriff muss geprüft werden, ob die gesuchte Position überhaupt gefunden wurde. Sonst entstehen ungültige Indizes.

String-Befehle im Kontext: Prüfen, Finden, Ausschneiden, Umformen

In den Arbeitsaufträgen werden Strings nicht nur gespeichert, sondern geprüft und zerlegt: Bei Benutzernamen geht es um Länge, Unterstrich und Namensbestandteile; bei E-Mail-Adressen um @-Zeichen, Punkte und Teilstrings. String-Methoden sind dafür Werkzeuge, mit denen Text als geordnete Zeichenfolge untersucht wird.

Methode Wozu? Kontextbeispiel Rückgabe
length()Länge prüfenusername.length() >= 8int
isEmpty()leere Eingabe prüfeneingabe.isEmpty()boolean
trim()Leerzeichen am Anfang/Ende entferneneingabe.trim()String
equals(...)Inhalte vergleicheneingabe.equals("ende")boolean
contains(...)Teiltext suchenemail.contains("@")boolean
indexOf(...)erste Position findenint at = email.indexOf("@");int
lastIndexOf(...)letzte Position findenemail.lastIndexOf("@")int
substring(start, ende)Teilstring ausschneidenemail.substring(0, at)String
charAt(index)einzelnes Zeichen lesentext.charAt(i)char
replace(...)Textstellen ersetzentext.replace(" ", "_")String
toUpperCase() / toLowerCase()Schreibweise vereinheitlichenname.toLowerCase()String
String email = "lea.mueller@example.de";

int at = email.indexOf("@");
boolean genauEinAt = at == email.lastIndexOf("@");
int punktNachAt = email.indexOf(".", at);

if (at > 0 && genauEinAt && punktNachAt > at + 1) {
    String benutzer = email.substring(0, at);
    String domain = email.substring(at + 1, punktNachAt);

    System.out.println("Benutzer: " + benutzer);
    System.out.println("Domain: " + domain);
} else {
    System.out.println("Die E-Mail-Adresse ist formal nicht gültig.");
}

Für die Arbeit mit Strings ist vor allem wichtig:

  • Strings sind Objekte und unveränderlich (immutable).
  • Methoden wie replace(...), toLowerCase(), trim() oder substring(...) verändern den ursprünglichen String nicht.
  • Soll das Ergebnis weiterverwendet werden, muss es gespeichert werden.
String name = " Lea ";
name.trim();        // Ergebnis wird verworfen
name = name.trim(); // Ergebnis wird gespeichert

Strings sind für Text optimiert und bieten dafür eigene Operationen. Gleichzeitig bleiben sie strukturiert genug, um Zeichenfolgen systematisch zu durchlaufen.

// Iteration über alle Zeichen eines Strings
for (int i = 0; i < kurs.length(); i++) {
    System.out.println(kurs.charAt(i));
}
Typische Stolperstellen
  • Indizes beginnen bei 0.
  • Der letzte gültige Index ist immer Länge minus eins.
  • indexOf(...) liefert -1, wenn der gesuchte Text nicht vorkommt.
  • substring(start, ende) enthält start, aber nicht ende.
  • substring(start, ende) kann Fehler auslösen, wenn die Indizes ungültig sind.
  • Strings sind unveränderlich; Methoden erzeugen meist neue Strings.
  • Arrays haben nach der Erzeugung eine feste Länge.
  • array.length ist ein Attribut ohne Klammern, string.length() ist eine Methode mit Klammern.

D) Gemeinsamkeiten von Arrays und Strings

  • Beide sind geordnet.
  • Beide können über Indizes betrachtet werden.
  • Beide lassen sich mit Schleifen durchlaufen.
  • Der Indexzugriff ist die Brücke zur algorithmischen Verarbeitung.
  • Unterschied: Arrays können Elemente verändern, Strings nicht direkt.

Diese gemeinsame Strukturperspektive ist entscheidend: Lernende betrachten Arrays und Strings nicht als isolierte Einzelthemen, sondern als Varianten derselben Grundidee „strukturierte Daten“.

E) Einordnung: primitive Datentypen, komplexe Strukturen und Ausblick

Im Unterschied zu primitiven Datentypen wie int oder boolean, die jeweils einen einzelnen Wert speichern, repräsentieren Arrays und Strings mehrere, strukturierte Werte in einer gemeinsamen Form.

Die Java-8-API stützt diese Einordnung: String bietet Methoden zum Prüfen, Suchen, Ausschneiden und Umformen von Zeichenfolgen; java.util.Arrays bündelt statische Hilfsmethoden, etwa für lesbare Ausgabe und elementare Array-Operationen.

Für die nächsten Kapitel ist diese Einordnung zentral: Verarbeitungsroutinen arbeiten häufig auf genau solchen Strukturen, etwa wenn Werte geprüft, gezählt, verändert oder ausgegeben werden. Zugleich ist der Blick nach vorne wichtig: Strings sind in Java Objekte, und komplexere Datenorganisation wird in der Qualifikationsphase systematisch über Objektstrukturen in Q1.1 und über Datenstrukturen in Q1.4 vertieft. Q2.1 ist der passende Anschluss, wenn aus solchen Strukturen ein fachliches Datenmodell entwickelt wird.

Damit ist die Datenbasis gelegt, auf der spätere algorithmische Verfahren in Q1.2 als Such- und Sortierstrategien untersucht werden können.

GUI und Ereignissteuerung
Grafische Benutzeroberflächen und ereignisgesteuerte Programmierung
Interaktion über Fenster, Eingaben und Aktionen

Eine grafische Benutzeroberfläche besteht aus sichtbaren Bausteinen. Einige Bausteine dienen der Eingabe, andere lösen Aktionen aus, wieder andere zeigen Ergebnisse an. Erst durch ihr Zusammenspiel entsteht eine interaktive Anwendung.

Eine GUI ist zugleich Präsentations- und Interaktionsschicht eines Programms: Sie nimmt Eingaben entgegen, macht Zustände sichtbar und löst Verarbeitungsschritte aus. Im Unterschied zur Konsole läuft die Interaktion nicht über eine feste Eingabezeile, sondern über Benutzeraktionen wie Klicks, Auswahlen oder Texteingaben.

Im Beispiel sind die Grundbausteine gut erkennbar: Das Fenster ist der äußere Rahmen der Anwendung. Darin strukturieren Bereiche/Container die Oberfläche in inhaltliche Gruppen. Ein Eingabefeld nimmt Werte auf, eine Schaltfläche (Button) startet eine Aktion, und ein Schriftfeld (Label) zeigt Ergebnisse an.

Beschriftete GUI Anhalteweg mit Fenster, Rahmen, Eingabefeld, Schaltfläche und Schriftfeld.
Bausteine der GUI „Anhalteweg“: Sichtbare Komponenten sind in einem Fenster und in Bereichen gruppiert.

Im Beispiel werden die Bausteine direkt auf den GUI-Ablauf bezogen: Eingabefelder liefern Werte, die Schaltfläche löst ein Ereignis aus, und Schriftfelder zeigen Ergebnisse. Ein Button ist dabei ein Auslöser, nicht die Verarbeitung selbst.

Nach dem EVA-Einstieg mit Konsolenprogrammen wird dieselbe Grundidee in grafischen Benutzeroberflächen unter Ereignissteuerung umgesetzt. Der Programmablauf ist dabei nicht mehr ausschließlich eine feste Folge von Konsoleneingaben und Ausgaben. Stattdessen wird zuerst eine Oberfläche aufgebaut; danach wartet das Programm auf Ereignisse wie einen Klick.

Eine grafische Benutzeroberfläche besteht aus sichtbaren Komponenten, die als Objekte modelliert sind. Jede Komponente besitzt Eigenschaften, Methoden und einen internen Zustand, der gelesen oder verändert werden kann. Eine GUI verbindet damit Darstellung, Eingabe und Reaktion auf Benutzerereignisse zu einem gemeinsamen Ablauf. In Java-Swing wird die Oberfläche aus Containern und Komponenten zusammengesetzt. In E3 steht dabei nicht professionelle Oberflächengestaltung im Mittelpunkt, sondern das Verstehen dieses Grundprinzips. Klasse, Objekt und Attribut werden hier nur angebahnt; Q1.1 entwickelt diese OOP-Begriffe systematisch weiter. Kurz gefasst: Eine GUI setzt EVA unter Ereignissteuerung um.

Hier kehren die vorherigen Kapitel in einer neuen Umgebung wieder: Variablen erscheinen als Eingabe- und Ausgabezustände, Ausdrücke als Berechnungen, Bedingungen als Prüfungen im Event-Handler, Methoden als Fachlogik und EVA als Ablauf von Benutzeraktion bis Ergebnisanzeige.

1. Oberfläche, Ereignissteuerung und Fachlogik

Eine einfache GUI-Anwendung lässt sich in drei Ebenen denken: Die Oberfläche nimmt Eingaben entgegen und zeigt Ergebnisse, die Ereignissteuerung reagiert auf Benutzeraktionen, und die Fachlogik führt Berechnungen und Prüfungen aus.

Drei Ebenen einer einfachen GUI-Anwendung
Ebene Aufgabe
Oberfläche Anzeigen, Eingaben aufnehmen und Zustände sichtbar machen
Ereignissteuerung Reaktion registrieren und beim Ereignis ausführen
Fachlogik Berechnungen, Prüfungen und Regeln unabhängig von der Oberfläche formulieren

GUI-Komponenten sind nicht die Fachlogik. Sie liefern Zustände oder zeigen Ergebnisse; die Verarbeitung bleibt als Fachlogik getrennt.

Der Event-Handler bildet die Vermittlungsschicht zwischen Oberfläche und Fachlogik: Er liest Zustände aus Komponenten, ruft eine passende Verarbeitungsmethode auf und schreibt das Ergebnis in die Oberfläche zurück.

Trennung von Oberfläche und Verarbeitung Zwei Bereiche zeigen links die Fachlogik mit Berechnungen und rechts die GUI mit Ein- und Ausgabe. Unten verbindet ein Pfeilablauf Benutzeraktion, Verarbeitung und Anzeige. Fachlogik GUI • Verarbeitung von Daten, Berechnungen • Beispiel: „Berechnung des Gehalts“ • Unabhängig von der Oberfläche • Eingabe und Ausgabe • Textfelder, Buttons, Labels • Unabhängig von der Fachlogik Benutzeraktion → Verarbeitung → Anzeige
Trennung von Oberfläche und Verarbeitung in einer GUI-Anwendung

2. Zentrales Denkmodell: linearer Ablauf und GUI-Ablauf

Das klassische EVA-Modell bleibt erhalten, aber der Programmablauf wird im GUI-Kontext durch Ereignisse gesteuert.

Konsolenprogramm (linear)
Start Eingabe Verarbeitung Ausgabe Ende

Der Ablauf folgt einer festen Reihenfolge von oben nach unten.

GUI-Programm (ereignisgesteuert)
Start Oberfläche bleibt aktiv

wartet auf Ereignisse

reagiert wiederholt im passenden Event-Handler

Lineare Konsolenprogramme folgen einer festen Kette. GUI-Programme bleiben aktiv und reagieren immer wieder auf Ereignisse.
EVA im GUI-Kontext
EVA-Schritt GUI-Umsetzung
Eingabe Zustände aus Komponenten lesen, z. B. getText() oder isSelected()
Verarbeitung Fachlogik ausführen, Bedingungen prüfen, Methoden aufrufen
Ausgabe Komponenten aktualisieren, z. B. setText(...)

Wichtig: Ein Button ist keine direkte Dateneingabe. Er ist ein Auslöser, der ein Ereignis erzeugt und damit die Verarbeitung startet.

EVA in einer grafischen Benutzeroberfläche: Textfeld und Button als Eingabe, Funktion als Verarbeitung, Label als Ausgabe.
EVA im GUI-Kontext: Nutzendeingaben und Klickereignisse werden verarbeitet und in einer Anzeige ausgegeben.

Damit eine GUI auf Ereignisse reagieren kann, müssen ihre Komponenten dauerhaft verfügbar sein. Deshalb werden wichtige Komponenten häufig als Attribute der Klasse gespeichert.

3. Hauptfenster, Container und Komponenten

Ein JFrame ist das Hauptfenster einer Swing-Anwendung. Komponenten werden darin nicht frei schwebend platziert, sondern in eine Container-Struktur eingefügt. Ein Container kann weitere Komponenten enthalten und strukturieren. Das Fenster ist der oberste Container; ein JPanel kann als innerer Container Komponenten gruppieren. Sichtbare Komponenten sind z. B. JLabel, JTextField, JButton oder JCheckBox. Typisch ist die Reihenfolge: Objekt erzeugen → konfigurieren → anordnen/positionieren → hinzufügen → später auswerten oder verändern.

Informatikfachlich bedeutet das: Fenster, Panels, Buttons und Textfelder sind Objekte mit Eigenschaften, Methoden und internem Zustand. Container strukturieren diese Objekte und erzeugen gemeinsam eine hierarchische Objektstruktur der Oberfläche.

import javax.swing.*;

public class ContainerStrukturDemo {
    public static void main(String[] args) {
        JFrame fenster = new JFrame("Container-Struktur");
        fenster.setSize(360, 220);
        fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        fenster.setLayout(null);

        JPanel panel = new JPanel();
        panel.setLayout(null);
        panel.setBounds(20, 20, 300, 120);

        JLabel beschriftung = new JLabel("Panel als innerer Container");
        beschriftung.setBounds(20, 20, 220, 25);
        panel.add(beschriftung);

        JButton button = new JButton("Aktion");
        button.setBounds(20, 60, 100, 25);
        panel.add(button);

        fenster.add(panel);
        fenster.setVisible(true);
    }
}
  • JFrame ist das Hauptfenster.
  • JPanel ist ein innerer Container.
  • JLabel und JButton werden dem Panel hinzugefügt.
  • Das Panel wird anschließend dem Fenster hinzugefügt.
  • Dadurch entsteht eine hierarchische Struktur aus Containern und Komponenten.
Hierarchie einer Swing-Oberfläche mit JFrame, JMenuBar, content pane, JPanel und Buttons.
Eine Swing-Oberfläche ist hierarchisch aufgebaut: Ein JFrame enthält eine Menüleiste und eine content pane. In der content pane liegen Komponenten oder weitere Container wie JPanel.

4. Bausteine einer einfachen Swing-GUI

Swing-Komponenten folgen einem gemeinsamen Muster: Der Konstruktor erzeugt ein Objekt, setBounds(...) beziehungsweise ein Layout-Manager bestimmt die Darstellung, und mit add(...) wird die Komponente in einen Container eingefügt.

Benötigte Importpakete für die Swing-Beispiele
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
JFrame – Fenster erzeugen
JFrame fenster = new JFrame("Login");
JLabel – Text ausgeben
JLabel lblInfo = new JLabel("Bitte anmelden");
JTextField – Eingabe aufnehmen
JTextField txtUser = new JTextField();
JButton – Ereignis auslösen
JButton btnLogin = new JButton("Anmelden");
setLayout(null) – absolute Positionierung aktivieren
fenster.setLayout(null);
setBounds(...) – Position und Größe festlegen
btnLogin.setBounds(80, 90, 120, 25);
add(...) – Komponente einfügen
fenster.add(btnLogin);
setVisible(true) – Fenster anzeigen
fenster.setVisible(true);

Die Codeboxen sind bewusst isoliert dargestellt. In einem vollständigen Programm müssen diese Bausteine in sinnvoller Reihenfolge zusammengesetzt werden. Für die Einführungsphase wird zunächst mit setLayout(null) und setBounds(...) gearbeitet, weil dadurch der Zusammenhang zwischen Objekt, Position und Anzeige besonders sichtbar bleibt.

Warum Komponenten oft Attribute sind

Eine lokale Variable ist außerhalb ihres Blocks beziehungsweise ihrer Methode nicht zugreifbar. Wichtige GUI-Komponenten werden deshalb oft als Attribute, also als Felder der Klasse, gespeichert: Der Konstruktor erzeugt und ordnet sie, der Listener liest oder verändert später dieselben Komponenten.

Benötigte Importpakete
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
1. Attribute deklarieren
private JTextField txtName;
private JLabel lblAusgabe;
2. Im Konstruktor erzeugen
public MeineGUI() {
    txtName = new JTextField(20);
    lblAusgabe = new JLabel("Noch keine Eingabe.");
}
3. Im Listener verwenden
public void actionPerformed(ActionEvent e) {
    String name = txtName.getText();
    lblAusgabe.setText("Hallo, " + name + "!");
}

Wenn Komponenten dauerhaft verfügbar sind, kann der Event-Handler mit ihnen arbeiten: Er liest Zustände aus, verarbeitet Werte und schreibt Ergebnisse zurück.

5. Zustände von GUI-Komponenten lesen und verändern

  • GUI-Komponenten sind Objekte mit internem Zustand.
  • get- und is-Methoden lesen Zustände.
  • set-Methoden verändern Zustände.
  • Die Komponente bleibt bestehen; nur ihr Zustand ändert sich.
  • setText("") löscht nicht das Objekt, sondern setzt den Textzustand auf die leere Zeichenkette.
Beispiele: Zustände lesen und verändern
Zustände lesen
Komponente Code
JTextField String text = feld.getText();
JLabel String info = label.getText();
JCheckBox boolean aktiv = check.isSelected();
JRadioButton boolean gewaehlt = radio.isSelected();
JComboBox
Ausblick
int index = combo.getSelectedIndex();
JSpinner
Ausblick
int wert = (int) spinner.getValue();
Zustände verändern
Komponente Code
JLabel label.setText("Fertig");
JTextField feld.setText("");
JCheckBox check.setSelected(true);
JRadioButton radio.setSelected(true);
JComboBox
Ausblick
combo.setSelectedIndex(2);
JSpinner
Ausblick
spinner.setValue(5);

6. Vertiefung: Spezielle Layout-Formen

Vertiefung: Spezielle Layout-Formen

Bisher wurde in E3 bewusst mit setLayout(null) und setBounds(...) gearbeitet, damit Positionen und Größen explizit sichtbar werden. In größeren Swing-Programmen werden stattdessen Layout-Manager eingesetzt. Sie ordnen Komponenten automatisch an und reagieren auf Fenstergrößen sowie die verfügbare Containerfläche.

In dieser Vertiefung werden drei zentrale Layouts aus der Swing-Grundausbildung betrachtet: FlowLayout, BorderLayout und GridLayout. Als kurzer Ausblick gelten außerdem BoxLayout, CardLayout und GridBagLayout, die hier nicht weiter vertieft werden.

FlowLayout – zeilenweise Anordnung

Komponenten werden zeilenweise von links nach rechts angeordnet. Wenn kein Platz mehr vorhanden ist, beginnt automatisch eine neue Zeile. Die sichtbare Anordnung hängt daher direkt von der Fensterbreite ab.

Hinweis: Das Beispiel nutzt hier extends JFrame, weil viele Swing-Quellen so kompakt erklären. Die bisherigen E3-Beispiele arbeiten weiterhin ohne Vererbung über ein separates JFrame-Objekt.

Schematische Darstellung eines FlowLayouts mit Umbruch in eine zweite Zeile.
FlowLayout ordnet Komponenten zeilenweise an; bei zu geringer Breite beginnt eine neue Zeile.
import javax.swing.*;
import java.awt.FlowLayout;

public class FlowLayoutDemo extends JFrame {
    public FlowLayoutDemo() {
        setTitle("FlowLayoutDemo");
        setSize(500, 160);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new FlowLayout(FlowLayout.LEFT));

        add(new JButton("Button 1"));
        add(new JButton("Button 2"));
        add(new JButton("Button 3"));
        add(new JButton("Long-Named Button 4"));
        add(new JButton("5"));

        setVisible(true);
    }

    public static void main(String[] args) {
        new FlowLayoutDemo();
    }
}
BorderLayout – fünf Bereiche

Die Containerfläche wird in fünf Bereiche eingeteilt: NORTH, WEST, SOUTH, EAST und CENTER. Bei Größenänderungen wächst besonders der CENTER-Bereich; die Randbereiche passen sich entsprechend an. Direkt pro Position kann höchstens eine Komponente eingefügt werden (für mehrere Elemente nutzt man z. B. ein zusätzliches JPanel).

Schematische Aufteilung eines BorderLayouts in fünf Bereiche.
BorderLayout teilt die Containerfläche in fünf Bereiche.
import javax.swing.*;
import java.awt.BorderLayout;

public class BorderLayoutDemo extends JFrame {
    public BorderLayoutDemo() {
        setTitle("BorderLayoutDemo");
        setSize(420, 240);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new BorderLayout());

        add(new JButton("North"), BorderLayout.NORTH);
        add(new JButton("West"), BorderLayout.WEST);
        add(new JButton("South"), BorderLayout.SOUTH);
        add(new JButton("East"), BorderLayout.EAST);
        add(new JButton("Center"), BorderLayout.CENTER);

        setVisible(true);
    }

    public static void main(String[] args) {
        new BorderLayoutDemo();
    }
}
GridLayout – gitterförmige Anordnung

Komponenten werden gitterförmig angeordnet. Jede Komponente ist gleich groß und nutzt den verfügbaren Platz vollständig aus. new GridLayout(0, 2) bedeutet dabei: beliebig viele Zeilen und genau zwei Spalten.

Schematische Darstellung eines GridLayouts mit zwei Spalten.
GridLayout ordnet Komponenten in gleich große Rasterzellen ein.
import javax.swing.*;
import java.awt.GridLayout;

public class GridLayoutDemo extends JFrame {
    public GridLayoutDemo() {
        setTitle("GridLayoutDemo");
        setSize(420, 220);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new GridLayout(0, 2));

        add(new JButton("Button 1"));
        add(new JButton("Button 2"));
        add(new JButton("Button 3"));
        add(new JButton("Long-Named Button 4"));
        add(new JButton("5"));

        setVisible(true);
    }

    public static void main(String[] args) {
        new GridLayoutDemo();
    }
}

7. Vertiefung: Weitere Swing-Komponenten

Vertiefung: Weitere Swing-Komponenten

Swing stellt viele weitere GUI-Komponenten bereit. In E3 werden davon nur ausgewählte Komponenten betrachtet. Die folgenden Beispiele sind optional und zeigen typische Eingabe-, Auswahl- und Strukturierungselemente. Alle Komponenten folgen demselben Grundprinzip: Objekt erzeugen, konfigurieren, positionieren, hinzufügen und bei Bedarf im Event-Handler auswerten.

Benötigtes Importpaket
import javax.swing.*;
JCheckBox – unabhängige Auswahl

Eine JCheckBox eignet sich für Optionen, die unabhängig voneinander ein- oder ausgeschaltet werden können. Die Eingabe wird als Wahrheitswert modelliert und mit isSelected() ausgewertet. Im EVA-Sinn liefert sie Eingabezustände, die in der Verarbeitung geprüft werden.

JCheckBox newsletter = new JCheckBox("Newsletter abonnieren");
newsletter.setBounds(20, 20, 220, 25);
fenster.add(newsletter);

boolean ausgewaehlt = newsletter.isSelected();
JRadioButton + ButtonGroup – genau eine Auswahl

JRadioButton wird verwendet, wenn aus mehreren Alternativen genau eine gewählt werden soll. Eine ButtonGroup organisiert die gegenseitige Ausschließlichkeit der Auswahl. Für EVA bedeutet das: klare Eingabeoptionen, deren Zustand im Event-Handler abgefragt werden kann.

JRadioButton klein = new JRadioButton("klein");
klein.setBounds(20, 20, 100, 25);

JRadioButton gross = new JRadioButton("groß");
gross.setBounds(20, 50, 100, 25);

ButtonGroup gruppe = new ButtonGroup();
gruppe.add(klein);
gruppe.add(gross);

fenster.add(klein);
fenster.add(gross);

if (gross.isSelected()) {
    ausgabe.setText("Groß wurde gewählt.");
}
JComboBox – Auswahl aus einer Liste

Eine JComboBox bietet eine kompakte Auswahl aus mehreren vorgegebenen Werten. Typisch ist die Auswertung mit getSelectedItem(). Dadurch werden freie Texteingaben reduziert und mögliche Eingabefehler im Eingabeschritt minimiert.

String[] farben = {"Rot", "Grün", "Blau"};
JComboBox<String> auswahl = new JComboBox<>(farben);
auswahl.setBounds(20, 20, 120, 25);
fenster.add(auswahl);

String farbe = (String) auswahl.getSelectedItem();
JTextArea – mehrzeilige Texteingabe

Eine JTextArea erlaubt längere oder mehrzeilige Eingaben. Mit getText() wird der gesamte Textinhalt ausgelesen. In EVA kann so umfangreichere Eingabe gesammelt und danach verarbeitet werden.

JTextArea textbereich = new JTextArea();
textbereich.setBounds(20, 20, 220, 80);
fenster.add(textbereich);

String text = textbereich.getText();
JPasswordField – verdeckte Texteingabe

Ein JPasswordField ist für verdeckte Eingaben gedacht. Die Zeichen werden nicht offen angezeigt; zur Auswertung dient typischerweise getPassword(), das ein char[] liefert. Hier wird dies didaktisch vereinfacht in einen String umgewandelt.

JPasswordField passwortFeld = new JPasswordField();
passwortFeld.setBounds(20, 20, 160, 25);
fenster.add(passwortFeld);

String passwort = new String(passwortFeld.getPassword());
JPanel – Komponenten gruppieren

Ein JPanel kann Komponenten gruppieren und später auch eigene Layouts enthalten. Es ist damit ein Strukturierungselement innerhalb des Hauptfensters und verdeutlicht das Container-Prinzip. In EVA unterstützt es vor allem den geordneten Aufbau der Eingabe- und Ausgabeelemente.

JPanel panel = new JPanel();
panel.setLayout(null);
panel.setBounds(10, 10, 250, 100);

JLabel label = new JLabel("Gruppe");
label.setBounds(20, 20, 100, 25);
panel.add(label);

fenster.add(panel);

Weitere Komponenten wie JList, JMenuBar, JOptionPane oder JSlider sind möglich, werden hier aber nur als Ausblick betrachtet. Entscheidend ist das Grundprinzip: passende Komponente auswählen, als Objekt erzeugen, konfigurieren, hinzufügen und über Methoden bzw. Ereignisse nutzen.

Zustände allein machen eine GUI noch nicht interaktiv. Erst durch Ereignisse wird festgelegt, wann diese Zustände gelesen oder verändert werden.

8. ActionListener und ActionEvent

Ereignisverarbeitung trennt den Aufbau der Oberfläche vom Verhalten des Programms. Der GUI-Aufbau beschreibt, welche Objekte sichtbar sind; der Listener beschreibt, wie auf ein Ereignis reagiert wird. Ein Ereignis ist z. B. ein Button-Klick oder eine Auswahländerung. Über addActionListener(...) wird eine Reaktion registriert. Die Methode actionPerformed(...) wird erst ausgeführt, wenn das Ereignis eintritt.

Ein Button ist damit Auslöser, nicht Datenspeicher und nicht die Verarbeitung selbst. Welche Verarbeitungsroutine beim Klick ausgeführt wird, steht im registrierten Listener.

Ereignismodell

Ereignisquelle → Ereignisobjekt → Listener → actionPerformed(...) → Reaktion

Button-Klick
    ↓
ActionEvent entsteht
    ↓
registrierter Listener reagiert
    ↓
actionPerformed(...) wird ausgeführt
Benötigte Importpakete
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
Listener registrieren
button.addActionListener(this);
Reaktion formulieren
public void actionPerformed(ActionEvent e) {
    label.setText("Geklickt");
}

Die Schreibweise this ist nur dann möglich, wenn das aktuelle Objekt selbst als Listener verwendet wird. Die Grundidee bleibt in beiden Schreibweisen gleich: Eine Reaktion wird registriert und später beim Ereignis ausgeführt.

btnLogin.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        // Dieser Block wird erst beim Klick auf den Button ausgeführt.
    }
});

ActionEvent e ist ein Ereignisobjekt mit Informationen über das ausgelöste Ereignis, zum Beispiel welche Komponente die Aktion ausgelöst hat. Für den Einstieg ist vor allem wichtig: Der Code in actionPerformed(...) läuft nicht beim Programmstart, sondern erst dann, wenn der Button angeklickt wird.

Object quelle = e.getSource();

Diese Information muss in einfachen Programmen nicht immer ausgewertet werden. Sie erklärt aber, warum actionPerformed(...) ein Ereignisobjekt als Parameter erhält.

Auch die in der Vertiefung gezeigten Komponenten können im Event-Handler ausgewertet werden, zum Beispiel mit isSelected(), getSelectedItem() oder getText().

Im Event-Handler werden Eingabezustände gelesen und Reaktionen koordiniert. Dort lassen sich bekannte Kontrollstrukturen wie if, else, Schleifen oder Methodenaufrufe verwenden. Die Fachlogik sollte aber nicht vollständig im Listener verschwinden: Ein Button-Klick kann eine Methode auslösen, die Berechnung oder Prüfung selbst bleibt als Verarbeitungsroutine benannt. Damit werden die Inhalte aus den vorherigen Kapiteln zu Methoden und Kontrollstrukturen direkt in den GUI-Kontext übertragen.

button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        String name = eingabe.getText();

        if (name.equals("")) {
            ausgabe.setText("Bitte Namen eingeben.");
        } else {
            ausgabe.setText("Hallo, " + name + "!");
        }
    }
});
  • getText() liest die Eingabe aus dem Textfeld.
  • if prüft eine Bedingung und unterscheidet zwischen leerer und nicht leerer Eingabe.
  • setText(...) setzt abhängig vom Ergebnis unterschiedliche Ausgaben.
  • Die Kontrollstruktur steht innerhalb von actionPerformed(...), weil sie erst beim Button-Klick ausgeführt werden soll.

9. Vom GUI-Aufbau zum Ereignisablauf: EVA mit Event-Handling

GUI-Programme bestehen aus Aufbau und Verhalten. Zum Aufbau gehören Fenster, Komponenten, Positionen und Container. Zum Verhalten gehören die Reaktion auf Ereignisse, das Lesen von Eingaben, die Verarbeitung und die Ausgabe. Der Event-Handler verbindet beides: Er arbeitet mit den sichtbaren Objekten, sobald ein Benutzerereignis eintritt.

Das folgende Minimalbeispiel kombiniert die vorherigen Bausteine vollständig und zeigt den Weg von Eingabe über Ereignis und Verarbeitung zur Ausgabe.

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class GuiEvaMinimal {
    public static void main(String[] args) {
        JFrame fenster = new JFrame("Anhalteweg");
        fenster.setSize(320, 160);
        fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        fenster.setLayout(null);

        JTextField eingabe = new JTextField();
        eingabe.setBounds(20, 20, 160, 25);
        fenster.add(eingabe);

        JButton button = new JButton("Berechnen");
        button.setBounds(190, 20, 100, 25);
        fenster.add(button);

        JLabel ausgabe = new JLabel("Noch keine Berechnung.");
        ausgabe.setBounds(20, 70, 260, 25);
        fenster.add(ausgabe);

        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                double v = Double.parseDouble(eingabe.getText());
                double weg = berechneAnhalteweg(v);
                ausgabe.setText("Anhalteweg: " + weg);
            }
        });

        fenster.setVisible(true);
    }

    public static double berechneAnhalteweg(double v) {
        return v * v / 100.0;
    }
}
  • Aufbau: JFrame, JTextField, JButton und JLabel werden erzeugt und hinzugefügt.
  • Ereignis: Ein Button-Klick startet actionPerformed(...).
  • Eingabe: getText() liest Text aus dem Textfeld, Double.parseDouble(...) macht daraus eine Zahl.
  • Verarbeitung: berechneAnhalteweg(...) kapselt die Berechnung.
  • Ausgabe: setText(...) aktualisiert das Label.
  • Trennung: Dieselbe Methode könnte auch aus einem Konsolenprogramm oder Test heraus aufgerufen werden.
Startzustand und Ereignis anzeigen
Startzustand
  • Textfeld enthält "50".
  • Label zeigt "Noch keine Berechnung.".
  • Button wartet auf einen Klick.
Ereignis

Der Benutzer klickt Berechnen. Dadurch startet der registrierte Event-Handler.

Event-Trace anzeigen
Schritt Anweisung / Aktion Wirkung
1actionPerformed(...)Der Event-Handler startet.
2eingabe.getText()Liefert "50".
3Double.parseDouble("50")Liefert 50.0.
4berechneAnhalteweg(50.0)Liefert 25.0.
5ausgabe.setText(...)Setzt den Labeltext.
Endzustand anzeigen
Textfeld

Bleibt "50".

Label

Zeigt "Anhalteweg: 25.0".

Deutung: Der Button berechnet nicht selbst. Er löst ein Ereignis aus. Der Event-Handler liest den Zustand des Textfelds, ruft die Fachlogik auf und schreibt das Ergebnis zurück in das Label.

Schnittstellen-Merksatz

Benutzeraktion → GUI-Komponente → Event-Handler → Verarbeitung → GUI-Ausgabe

Die GUI ist die Schnittstelle zwischen Benutzer und Programm. Der Event-Handler ist die Schnittstelle zwischen Oberfläche und Fachlogik: Er liest Zustände aus Komponenten, ruft Verarbeitung auf und schreibt Ergebnisse zurück.

Für größere Programme gilt: Die Oberfläche steuert Ein- und Ausgabe. Berechnungen und Prüfungen sollten möglichst in getrennten Methoden liegen, damit der Event-Handler als Vermittlungsschicht übersichtlich bleibt. Das betrifft zum Beispiel Gehalt, Bremsweg oder Prüfregeln.

Typische Fehlvorstellungen beim Event-Handling
Benötigte Importpakete
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
Ein Button speichert Fachinformation.

Ein Button ist Auslöser, nicht Datenspeicher. Die eigentlichen Daten stehen z. B. in Textfeldern, Labels oder Variablen.

// Der Button löst nur aus.
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        String name = eingabe.getText();
        ausgabe.setText("Hallo, " + name + "!");
    }
});
actionPerformed(...) läuft beim Programmstart.

Der Code in actionPerformed(...) wird erst ausgeführt, wenn das registrierte Ereignis eintritt.

System.out.println("Programmstart");

button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Button wurde geklickt");
    }
});
setText(...) verändert automatisch die Fachlogik.

setText(...) verändert nur den Textzustand der Komponente.

double summe = a + b;                 // Fachlogik
ausgabe.setText("Summe: " + summe);   // GUI-Ausgabe
Ein Klick startet das ganze Programm neu.

Ein Klick startet nicht main(...) neu.

public static void main(String[] args) {
    // Wird beim Programmstart ausgeführt.
}

public void actionPerformed(ActionEvent e) {
    // Wird beim Klick ausgeführt.
}
GUI-Code und Verarbeitung müssen immer zusammen im Listener stehen.

Bei größeren Programmen sollte Fachlogik ausgelagert werden.

button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        double geschwindigkeit =
            Double.parseDouble(eingabe.getText());

        double anhalteweg =
            berechneAnhalteweg(geschwindigkeit);

        ausgabe.setText(
            "Anhalteweg: " + anhalteweg
        );
    }
});

public static double berechneAnhalteweg(double v) {
    return v * v / 100.0;
}

10. Weitere Beispiele zur Vertiefung

Die folgenden größeren Anwendungsbeispiele vertiefen dieselbe Leitidee: sichtbare Eingabe und Ausgabe, Auslösung durch Benutzerereignisse und Verarbeitung in passenden Methoden.

Variantenbeispiel: Begrüßung mit Texteingabe
Benötigte Importpakete
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        String name = eingabe.getText().trim();

        if (name.equals("")) {
            name = "Gast";
        }

        ausgabe.setText("Hallo, " + name + "!");
    }
});
Weiteres Beispiel: Addition zweier Zahlen
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class GuiAddition {
    public static void main(String[] args) {
        JFrame fenster = new JFrame("Addition");
        fenster.setSize(360, 180);
        fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        fenster.setLayout(null);

        JTextField eingabeA = new JTextField();
        eingabeA.setBounds(20, 20, 80, 25);
        fenster.add(eingabeA);

        JTextField eingabeB = new JTextField();
        eingabeB.setBounds(110, 20, 80, 25);
        fenster.add(eingabeB);

        JButton button = new JButton("Addieren");
        button.setBounds(200, 20, 110, 25);
        fenster.add(button);

        JLabel ausgabe = new JLabel("Noch kein Ergebnis.");
        ausgabe.setBounds(20, 70, 280, 25);
        fenster.add(ausgabe);

        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                double a = Double.parseDouble(eingabeA.getText());
                double b = Double.parseDouble(eingabeB.getText());
                double summe = a + b;
                ausgabe.setText("Summe: " + summe);
            }
        });

        fenster.setVisible(true);
    }
}

11. Weiterführende Dokumentation

Die hier behandelten Inhalte sind eine didaktische Auswahl. Insbesondere Hauptfenster/Container, Swing-Komponenten, Layout-Manager und Ereignisverarbeitung wurden fachlich reduziert übernommen. Swing umfasst deutlich mehr Themen wie Dialogfenster, Zeichnen mit paintComponent, GUI-Builder, Threads oder MVC; diese werden hier nur als Ausblick genannt. Die fachliche Struktur orientiert sich unter anderem an der Vorlesungsunterlage Grafische Benutzeroberflächen mit Swing von O. Bittel, HTWG Konstanz. Weitere Details finden sich in der offiziellen Java-Dokumentation:

Diese Bausteine führen zum Abschlussgedanken: Aus strukturierten Abläufen und Methoden entstehen benannte Verarbeitungsroutinen, an die Q1.2 und Q1.3 fachlich anschließen.

Algorithmen
Von Methoden zu algorithmischen Routinen
Programmierte Verarbeitung als Vorform algorithmischen Denkens

E3 entwickelt noch keine formale Algorithmusanalyse. Die Seite bereitet den Algorithmus-Begriff vor, indem Verarbeitung klar strukturiert wird: Anweisungen werden durch Kontrollstrukturen geordnet, wiederkehrende Folgen werden in Methoden gekapselt, und EVA macht Eingabe, Verarbeitung und Ausgabe als zusammenhängendes Funktionsmodell lesbar.

Eine Methode kann in diesem Sinn als benannte Verarbeitungsroutine gelesen werden. Sie besitzt Eingaben, Verarbeitungsschritte, Kontrollstrukturen und ein Ergebnis. In GUI-Systemen wird dieselbe Routine ereignisgesteuert ausgelöst: Benutzeraktion → Eingabezustand lesen → Verarbeitung ausführen → Ausgabe aktualisieren. Die systematische Untersuchung als Verfahren folgt in Q1.2.

Bereich Leitfrage
E3 Wie strukturiere ich Verarbeitung in einem Programm?
Q1.2 Welche Such- oder Sortierstrategie löst ein Problem effizient?
Q1.3 Kann ich ein Problem durch kleinere Probleme derselben Art beschreiben?

Die konkrete Ausarbeitung von Such- und Sortieralgorithmen gehört deshalb nach Q1.2: Dort werden Voraussetzungen, Darstellungen, Korrektheit, Laufzeit und Effizienz systematisch verglichen. Q1.3 verschiebt anschließend den Blick auf rekursive Problemstruktur, Teilprobleme, Basisfall und Rekursionsschritt.

Diagnoseperspektive: Programmieren als prüfende Praxis

Programmieren bedeutet in E3 nicht nur, Code zu schreiben. Entscheidend ist, die Wirkung einer Anweisung, eines Ausdrucks oder einer Methode prüfen zu können. Fehler werden deshalb nach ihrer Entstehungsstelle gelesen.

Fehlerart Beispiel Diagnosefrage
Syntaxfehler Semikolon fehlt Meldet der Compiler einen Fehler?
Laufzeitfehler ungültiger Arrayindex Welche Werte liegen beim Zugriff vor?
Logikfehler falsche Bedingung Wird der Ausdruck richtig ausgewertet?
Eingabefehler Text statt Zahl Wird die Eingabe geprüft oder umgewandelt?
GUI-Fehler Button tut nichts Ist ein Listener registriert?
Methodenfehler Rückgabewert wird nicht gespeichert Wird return an der Aufrufstelle genutzt?