Modul 2 von 6
Programmieren lernen
Programmieren ist keine Begabung, sondern eine Fertigkeit wie Autofahren: Am Anfang musst du über jeden Handgriff nachdenken, nach einiger Zeit machst du ihn nebenbei. Der einzige Weg dorthin führt über das Selbertippen. Jedes Beispiel auf dieser Seite kannst du sofort ausführen und verändern.
Im Studium wirst du wahrscheinlich mit Java anfangen, bei SAP später mit ABAP arbeiten. Hier lernst du mit JavaScript - aus einem praktischen Grund: Es läuft in jedem Browser, du musst nichts installieren und siehst das Ergebnis sofort.
Das ist kein Umweg. Variablen, Schleifen, Funktionen und Objekte funktionieren in allen drei Sprachen gleich - nur die Schreibweise unterscheidet sich. Zu jedem Thema findest du deshalb einen Vergleich mit Java und Python.
1. Was ist ein Programm?
Ein Programm ist eine Liste von Anweisungen, die von oben nach unten abgearbeitet werden. Mehr ist es im Kern nicht. Alles Weitere - Verzweigungen, Schleifen, Funktionen - sind nur Regeln, die diese Reihenfolge steuern.
Ein Rezept sagt: Backofen vorheizen, Mehl abwiegen, Eier unterrühren, 40 Minuten backen. Ein Programm sagt: Wert einlesen, prüfen, umrechnen, ausgeben. Der Unterschied ist, dass ein Koch mitdenkt und der Computer nicht. Steht "40 Minuten" da, wartet er 40 Minuten - auch wenn der Kuchen schon schwarz ist.
Dein erstes Programm
console.log(...) gibt etwas aus. Drück auf Ausführen und schau,
was passiert. Ändere danach den Text und führ es noch einmal aus.
- Eine vergessene schließende Klammer oder ein fehlendes Anführungszeichen.
- Groß- und Kleinschreibung:
Console.logfunktioniert nicht,console.logschon. Der Computer ist da gnadenlos. - Deutsche Anführungszeichen („…") statt gerader ("…"). Passiert oft beim Kopieren aus Word.
Lösch versuchsweise ein Anführungszeichen im Beispiel oben und führ es aus. Du
bekommst so etwas wie SyntaxError: Invalid or unexpected token. Der
Computer sagt dir damit: "In dieser Zeile steht etwas, das ich nicht deuten kann."
Gewöhn dir früh an, Fehlermeldungen zu lesen statt sie wegzuklicken - das ist der
größte einzelne Unterschied zwischen Anfängern und Fortgeschrittenen.
2. Variablen und Datentypen
Eine Variable ist ein benannter Behälter für einen Wert. Du legst etwas hinein, holst es später wieder heraus und kannst den Inhalt austauschen.
Auf der Schublade steht kundenname, darin liegt der Zettel "Meier".
Später kannst du den Zettel austauschen - die Beschriftung bleibt. Deshalb heißt es
Variable: veränderlich.
let alter = 19; // eine Zahl
const name = "Sarah"; // ein Text, unveränderlich
let istEingeschrieben = true; // ein Wahrheitswert
const für Werte, die sich nie ändern. let für alles
andere. Nimm im Zweifel const - dann meckert der Computer, falls du den Wert
versehentlich überschreibst, und du findest den Fehler sofort statt in drei Stunden.
(Das alte var solltest du nicht mehr verwenden.)
Die wichtigsten Datentypen
| Typ | Was drinsteht | Beispiel | In Java heißt es |
|---|---|---|---|
| Zahl | ganze und Kommazahlen | 42, 3.14 | int, double |
| Text (String) | Zeichenketten in Anführungszeichen | "Hallo" | String |
| Wahrheitswert | nur true oder false | true | boolean |
| Array | eine Liste von Werten | [1, 2, 3] | int[], List |
| Objekt | Werte mit Namen | { name: "Meier" } | eigene Klasse |
| null | ausdrücklich kein Wert | null | null |
Führ das nächste Beispiel aus: 0.1 + 0.2 ergibt nicht 0.3, sondern
0.30000000000000004. Das ist kein Fehler dieser Sprache, sondern gilt in Java,
Python und fast überall. Der Grund: 0,1 lässt sich im Binärsystem nicht exakt
darstellen, genauso wenig wie 1/3 im Dezimalsystem. Deshalb rechnet man
Geldbeträge nie mit Kommazahlen, sondern in Cent als ganze Zahlen oder mit
speziellen Dezimaltypen. In Buchhaltungssystemen wie SAP ist das eine harte Regel.
3. Rechnen und Vergleichen
| Zeichen | Bedeutung | Beispiel | Ergebnis |
|---|---|---|---|
+ - * / | Grundrechenarten | 7 / 2 | 3.5 |
% | Rest der Division | 7 % 2 | 1 |
=== | ist gleich | 3 === 3 | true |
!== | ist ungleich | 3 !== 4 | true |
< > <= >= | Größenvergleich | 5 >= 5 | true |
&& | logisches UND | true && false | false |
|| | logisches ODER | true || false | true |
! | Verneinung | !true | false |
= weist zu: "schreib das da hinein".
=== vergleicht: "ist das dasselbe?"
Das zu verwechseln ist der Klassiker unter den Anfängerfehlern - und in manchen
Sprachen ergibt if (x = 5) sogar ein gültiges, aber falsches Programm.
% liefert den Rest. Damit prüfst du Teilbarkeit: zahl % 2 === 0
ist genau dann wahr, wenn die Zahl gerade ist. Mit % 3 teilst du Daten
gleichmäßig auf drei Server auf. Dieselbe Idee steckt hinter Prüfziffern von IBAN
und Barcodes.
4. Verzweigungen: if und else
Bis jetzt lief jedes Programm stur von oben nach unten. Mit if trifft es
Entscheidungen.
if (bedingung) {
// läuft nur, wenn die Bedingung wahr ist
} else {
// läuft in allen anderen Fällen
}
Ein Zug fährt auf eine Weiche zu. Die Bedingung entscheidet, welches Gleis er nimmt. Danach fährt er auf jeden Fall weiter - nur eben auf einem von zwei Wegen.
Mehrere Fälle hängt man mit else if aneinander. Wichtig: Die Prüfung
läuft von oben nach unten und hört beim ersten Treffer auf.
Die Reihenfolge ist deshalb nicht beliebig.
Stünde umsatz >= 1000 ganz oben, bekäme jeder Kunde über 1000 Euro nur
5 Prozent - die späteren Zweige würden nie erreicht. Bei gestaffelten Bedingungen
gilt: von der engsten zur weitesten prüfen. Vertausch im Beispiel oben
testweise die Zweige und schau, was passiert.
5. Schleifen: Dinge wiederholen
Eine Schleife wiederholt einen Block, solange eine Bedingung gilt. Ohne Schleifen müsstest du für 5000 Rechnungspositionen 5000 Zeilen schreiben.
Die for-Schleife
for (let i = 0; i < 5; i++) {
console.log(i);
}
// ┬ ┬ ┬
// │ │ └─ nach jedem Durchlauf: i um 1 erhöhen
// │ └────────── solange das gilt, weiterlaufen
// └─────────────────── Startwert
In fast allen Programmiersprachen wird ab 0 gezählt. Eine Liste mit 5 Einträgen hat
die Positionen 0, 1, 2, 3, 4 - nicht 1 bis 5. Der letzte gültige Index ist
also immer länge - 1. Fast jeder Anfängerfehler bei Schleifen ist ein
Vertun um genau eins.
Die while-Schleife
for nimmt man, wenn die Anzahl der Durchläufe vorher feststeht,
while, wenn nicht - etwa "solange noch Daten kommen".
Wenn die Abbruchbedingung nie eintritt, läuft die Schleife ewig. Auf dieser Seite wird der Code nach 4 Sekunden abgebrochen, es kann also nichts passieren - probier es ruhig aus. Im Studium ist eine hängende Endlosschleife eine Erfahrung, die jeder mindestens einmal macht.
Aufgabe: Summe berechnen
Schreib eine Schleife, die alle Zahlen von 1 bis 100 zusammenzählt, und leg das
Ergebnis in summe ab. Der Prüfen-Knopf sagt dir, ob es stimmt.
Lösung anzeigen
let summe = 0;
for (let i = 1; i <= 100; i++) {
summe = summe + i; // kürzer: summe += i;
}
console.log("Summe:", summe); // 5050
Übrigens: Der Mathematiker Gauß soll diese Aufgabe als Kind ohne Schleife gelöst haben. Es gibt eine Formel dafür: n · (n+1) / 2, also 100 · 101 / 2 = 5050. Eine Rechnung statt hundert - genau darum geht es in Modul 3.
6. Funktionen
Eine Funktion ist ein benannter Codeblock, den du beliebig oft aufrufen kannst. Sie nimmt Werte entgegen (Parameter) und gibt einen Wert zurück (Rückgabewert).
Du gibst Bohnen und Wasser hinein (Parameter), drückst den Knopf (Aufruf) und bekommst Kaffee heraus (Rückgabewert). Wie sie innen arbeitet, musst du nicht wissen. Genau das ist der Zweck: Komplexität hinter einem Namen verstecken.
function bruttoPreis(netto, steuersatz) {
return netto * (1 + steuersatz / 100);
}
const preis = bruttoPreis(100, 19); // 119
- Nicht wiederholen: Ändert sich der Steuersatz, änderst du eine Stelle statt vierzig.
- Namen erklären:
bruttoPreis(100, 19)versteht man auch nach einem halben Jahr noch,100 * 1.19nicht. - Prüfbar: Eine Funktion mit klarer Ein- und Ausgabe kann man automatisch testen - genau das macht der Prüfen-Knopf hier.
Aufgabe: Rabattfunktion
Schreib eine Funktion rabattPreis(preis, prozent), die den Preis nach
Abzug des Rabatts zurückgibt. Bei 100 Euro und 20 Prozent sollen 80 herauskommen.
Lösung anzeigen
function rabattPreis(preis, prozent) {
return preis - (preis * prozent / 100);
}
// gleichwertig und etwas eleganter:
function rabattPreis(preis, prozent) {
return preis * (1 - prozent / 100);
}
Das häufigste Missgeschick hier: das return vergessen. Ohne return
gibt eine Funktion undefined zurück, auch wenn innen alles richtig
gerechnet wurde.
7. Listen und Objekte
Einzelne Variablen reichen nicht weit. Echte Programme arbeiten mit Sammlungen.
Arrays: eine nummerierte Liste
const preise = [10, 25, 7, 42];
preise[0] // 10 - das erste Element hat den Index 0
preise.length // 4 - Anzahl der Elemente
preise[preise.length - 1] // 42 - das letzte Element
Objekte: Werte mit Namen
Bei einem Kunden willst du nicht wissen, was an Position 2 steht, sondern was der
ort ist. Dafür gibt es Objekte:
const kunde = {
nummer: 4711,
name: "Meier GmbH",
ort: "Walldorf",
umsatz: 125000,
};
kunde.name // "Meier GmbH"
kunde.umsatz // 125000
Array, wenn du mehrere gleichartige Dinge hast (alle Kunden).
Objekt, wenn ein Ding mehrere unterschiedliche Eigenschaften hat (ein Kunde).
In der Praxis kombiniert man beides: ein Array von Objekten. Genau so sieht eine
Datenbanktabelle aus - und genau so kommen Daten aus einer Schnittstelle zurück.
filter, map und reduce sind genau das, was
SQL mit WHERE, SELECT und SUM macht - nur im
Programmcode statt in der Datenbank. Wenn du Modul 4 erreichst, wirst du das
Muster wiedererkennen.
8. Objektorientierung
Bei größeren Programmen reicht es nicht, Daten und Funktionen lose nebeneinander zu legen. Die objektorientierte Programmierung (OOP) bündelt beides: Daten und die dazu passenden Funktionen wandern in eine Klasse.
Eine Klasse ist der Bauplan, ein Objekt das fertige Haus. Aus einem Bauplan kann man beliebig viele Häuser bauen - jedes mit eigener Adresse und eigener Wandfarbe, aber alle mit demselben Grundriss. Das Erzeugen eines Objekts aus einer Klasse heißt Instanziierung.
Die vier Grundprinzipien
Die Daten eines Objekts sind vor direktem Zugriff von außen geschützt. Änderungen laufen über Methoden, die prüfen können - so kann kein Konto einen negativen Bestand bekommen, nur weil jemand von außen hineingeschrieben hat.
Eine Klasse kann Eigenschaften einer anderen übernehmen. Firmenkunde
erbt alles von Kunde und ergänzt die Handelsregisternummer, statt
alles zu wiederholen.
Verschiedene Klassen reagieren unterschiedlich auf denselben Aufruf.
rabatt() rechnet beim Privatkunden anders als beim Firmenkunden -
der aufrufende Code muss den Unterschied nicht kennen.
Ein Modell bildet nur das ab, was für die Aufgabe zählt. Ein Kunde im Rechnungssystem hat eine Steuernummer, aber keine Augenfarbe.
Objektorientierung ist das beherrschende Modell in Java und auch in modernem ABAP (dort heißt es ABAP Objects). Die vier Prinzipien oben sind eine Standardfrage in mündlichen Prüfungen - lern sie mit je einem eigenen Beispiel, nicht mit der Definition.
9. Fehler finden und behandeln
Programmieren besteht zum größeren Teil aus Fehlersuche. Das ist kein Zeichen von Unfähigkeit, sondern der Normalzustand des Berufs. Es hilft, drei Fehlerarten zu unterscheiden:
| Art | Wann er auffällt | Beispiel |
|---|---|---|
| Syntaxfehler | sofort, das Programm startet gar nicht | fehlende Klammer |
| Laufzeitfehler | während der Ausführung, das Programm bricht ab | Zugriff auf ein Element, das es nicht gibt |
| Logikfehler | gar nicht - das Ergebnis ist einfach falsch | < statt <= geschrieben |
Ein abgestürztes Programm merkt jeder. Eine Rechnung, die um einen Cent daneben liegt, fällt vielleicht erst nach Monaten auf - dann aber teuer. Deshalb schreibt man Tests.
Die Fehlersuche in vier Schritten
- Fehlermeldung lesen. Sie nennt Datei und Zeile. Das klingt banal, wird aber ständig übersprungen.
- Ausgaben einbauen.
console.logvor und hinter der verdächtigen Stelle zeigt dir, welche Werte tatsächlich ankommen. Fast immer ist es nicht der, den du erwartet hast. - Halbieren. Kommentier die Hälfte des Codes aus. Tritt der Fehler noch auf? So grenzt du die Stelle in wenigen Schritten ein.
- Laut erklären. Erklär den Code einer anderen Person - oder einer Gummiente auf dem Schreibtisch. Beim Formulieren fällt einem der Fehler auffallend oft selbst auf. Der Trick heißt tatsächlich "Rubber Duck Debugging".
Fehler abfangen mit try/catch
Manche Fehler kann man nicht verhindern - eine Netzwerkverbindung bricht ab, eine Datei fehlt. Damit das Programm dann nicht abstürzt, fängt man sie ab:
Dieselbe Sache in drei Sprachen
Damit dich der Wechsel im Studium nicht überrascht: Hier ist derselbe Gedanke - eine Funktion, die Werte aus einer Liste summiert - dreimal aufgeschrieben.
function summe(zahlen) {
let s = 0;
for (const z of zahlen) {
s += z;
}
return s;
}
public static int summe(int[] zahlen) {
int s = 0;
for (int z : zahlen) {
s += z;
}
return s;
}
def summe(zahlen):
s = 0
for z in zahlen:
s += z
return s
Unterschiedlich sind Klammern, Semikolons und die Frage, ob Datentypen hingeschrieben werden müssen. Identisch ist der Gedanke: Startwert setzen, durchlaufen, aufsummieren, zurückgeben. Wenn du das Denken beherrschst, ist eine neue Sprache eine Sache von Tagen, nicht von Monaten.
Übungen
Aufgabe 1 · leicht
Schreib eine Funktion istGerade(zahl), die true zurückgibt,
wenn die Zahl gerade ist.
Lösung anzeigen
function istGerade(zahl) {
return zahl % 2 === 0;
}
Nicht nötig ist if (zahl % 2 === 0) { return true; } else { return false; }
- der Vergleich liefert bereits true oder false.
Aufgabe 2 · mittel
Schreib groessterWert(zahlen), die den größten Wert einer Liste
zurückgibt - ohne Math.max zu benutzen.
Lösung anzeigen
function groessterWert(zahlen) {
let groesster = zahlen[0];
for (const z of zahlen) {
if (z > groesster) {
groesster = z;
}
}
return groesster;
}
Die entscheidende Stelle: Der Startwert muss das erste Element sein, nicht 0. Sonst liefert die Funktion bei lauter negativen Zahlen fälschlich 0 - genau deshalb ist der zweite Test in der Liste.
Aufgabe 3 · mittel
Schreib zaehleGrosskunden(kunden), die zählt, wie viele Kunden mehr als
100 000 Euro Umsatz haben.
Lösung anzeigen
function zaehleGrosskunden(kunden) {
let anzahl = 0;
for (const k of kunden) {
if (k.umsatz > 100000) {
anzahl++;
}
}
return anzahl;
}
// kürzer:
function zaehleGrosskunden(kunden) {
return kunden.filter(k => k.umsatz > 100000).length;
}
Der dritte Test prüft die Grenze: "mehr als 100 000" heißt
>, nicht >=. Solche Grenzfälle sind in
Klausuren und in echten Projekten die häufigste Fehlerquelle.
Aufgabe 4 · schwer
Schreib istPrimzahl(n). Eine Primzahl ist nur durch 1 und sich selbst
teilbar. Achtung bei den Randfällen: 0 und 1 sind keine Primzahlen, 2 ist die
kleinste.
Lösung anzeigen
function istPrimzahl(n) {
if (n < 2) return false;
for (let i = 2; i * i <= n; i++) {
if (n % i === 0) return false; // Teiler gefunden
}
return true;
}
Warum i * i <= n und nicht i < n? Hat eine
Zahl einen Teiler, der größer als ihre Wurzel ist, dann gibt es dazu zwangsläufig
einen zweiten, der kleiner ist - und den hätte die Schleife längst gefunden. Bei
n = 1 000 000 sind das 1000 Durchläufe statt einer Million.
Das ist ein erster Vorgeschmack auf Modul 3: Dieselbe Aufgabe, hundertfach schneller, nur durch eine bessere Abbruchbedingung.
Selbsttest
Karteikarten zu diesem Modul
Wenn du tiefer einsteigen willst
- "Java ist auch eine Insel" von Christian Ullenboom - kostenlos online lesbar und das gängigste deutschsprachige Java-Buch. Passend, wenn deine Vorlesung mit Java startet.
- exercism.org oder Codewars - kleine Übungsaufgaben mit automatischer Prüfung. Zwei Aufgaben am Tag bringen mehr als ein Wochenende Videos.
- "Clean Code" von Robert C. Martin - ab dem zweiten Semester interessant, wenn du merkst, dass funktionierender Code und guter Code zwei Dinge sind.