michael.eichberg@dhbw-mannheim.de, Raum 149B
1.0
Die Folien sind teilweise inspiriert von oder basierend auf Lehrmaterial von Prof. Dr. M. Matt bzw. Prof. C. Binning.
HelloWorld.java[1]
void main() {
println("Hello World!");
}
Die Datei enthält ein einfaches Java-Programm, das den Text Hello World! auf der Konsole ausgibt.
In der ersten Zeile wird die Methode main
definiert. Diese ist die Einstiegsmethode in das Programm. Der Text Hello World! wird mit der Methode println
auf der Konsole ausgegeben. Die Methoden print
, und println
sind in Java Skripten immer verfügbar (bei Verwendung von --enable-preview (Java 23)) und geben den übergebenen Text auf der Konsole aus. Die Methode print
tut dies ohne und die Methode println
mit Zeilenumbruch (\\n) am Ende.
HelloYou.java[2]
void main() {
println("Hello " + readln("What is your name? "));
}
Mit Hilfe von readln können Sie von der Konsole lesen. In Java Skripten ist readln immer verfügbar. Das Programm gibt den Text Hello gefolgt von dem eingegebenen Text aus. Die Methode readln gibt erst den übergebenen String aus und liest dann eine Zeile von der Konsole ein. Der eingelesene Text wird dann an das Wort "Hello " angehängt (mittels des "+" Operators) und als ganzes zurückgegeben.
Lesen von und Schreiben auf die Konsole
Schreiben Sie ein Java-Programm (GutenMorgen.java), das erst nach dem Namen des Nutzers X fragt und dann Guten Morgen X! auf der Konsole ausgibt. Beachten Sie dabei, dass der Text X durch den eingegebenen Namen ersetzt wird und am Ende ein Ausrufezeichen steht.
Als zweites soll das selbe Programm dann nach dem Wohnort Y des Nutzers fragen und dann Y ist wirklich schön! auf der Konsole ausgeben.
Schreiben Sie das Programm und führen Sie es aus!
Hinweis
Vorgehensweise:
Stellen Sie sicher, dass Java korrekt installiert ist. Öffnen Sie dazu die Konsole und geben Sie java --version ein.
Öffnen Sie einen Texteditor (z. B. Visual Studio Code oder ZED oder ...)
Schreiben Sie den Rumpf des Programms: void main() { <IHR CODE> }
Ersetzen Sie <IHR CODE> durch den Code, der den Nutzer nach seinem Namen X fragt und dann "Guten Morgen X!" ausgibt.
Führen Sie den Code aus in dem Sie die Konsole/ein Terminal öffnen und dort: java --enable-preview GutenMorgen.java
ausführen.
Dienen der Codedokumentation und werden vom Compiler ignoriert.
ganze Zahlen (byte, int, long), Fließkommazahlen (float, double), Zeichen (char, byte), Wahrheitswerte (boolean)
Konstante Wert (z.B. 42, 3.14, 'A', "Hello World!")
Speichern eines Wertes in einer Variable
(Eine benannten Stelle im Speicher)
dienen der Berechnung von Werten mit Hilfe von Variablen, Literalen und Operatoren
dienen der Ablaufsteuerung mit Hilfe von Schleifen (while
, do-while
, for
) und Verzweigungen (if
-else
, switch
-case
)
Methoden (Prozeduren und Funktionen), die eine bestimmte Funktionalität wiederverwendbar bereitstellen
Kommentare dienen der Dokumentation des Codes und helfen anderen Entwicklern den Code zu verstehen.
In Java unterscheiden wir folgende Arten von Kommentaren:
Einzeilige Kommentare, die mit // beginnen und bis zum Ende der Zeile gehen.
Mehrzeilige Kommentare, die mit /* beginnen und mit */ enden.
Kommentare, die mit /** beginnen und mit */ enden, sind so genannte JavaDoc Kommentare und dienen der Erzeugung von Dokumentation.
[ab Java 23] Mehrzeilige Kommentare, bei der jede Zeile mit /// beginnt, werden als Markdown basierte JavaDoc Kommentare interpretiert.
Beispiel (ab Java 1.0 - spezifische Tags und HTML)
/**
* Berechnet die Fakultät von n.
*
* @param n die Zahl, von der die Fakultät berechnet werden soll; (0 <= n <= 20).
* @return die Fakultät von n.
*/
long fak(long n){ // TODO mögliche Fehlerfälle abfangen
/* Die Verwendung von long als Datentyp limitiert uns auf n <= 20;
durch den wechsel von long auf double könnten wir bis n <= 170 rechnen;
sind aber unpräziser. */
if (n == 0) return 1;
else return n * fak(n-1);
}
Beispiel (ab Java 23 - spezifische Tags und Markdown)
/// Berechnet die Fakultät von n.
///
/// @param n die Zahl, von der die Fakultät berechnet werden soll;/
/// (*0 <= n <= 20*).
/// @return _die Fakultät von n_.
long fak(long n){ // TODO mögliche Fehlerfälle abfangen
/* Die Verwendung von long als Datentyp limitiert uns auf n <= 20;
durch den wechsel von long auf double könnten wir bis n <= 170 rechnen;
sind aber unpräziser. */
if (n == 0) return 1;
else return n * fak(n-1);
}
Erzeugte Dokumentation (mit Java 23)
JavaDoc tags
Dokumentiert einen Parameter einer Methode.
Dokumentiert den Rückgabewert einer Methode.
Die Java Shell (jshell) ist ein interaktives Werkzeug, das es ermöglicht Java-Code (insbesondere kurze Snippets) direkt auszuführen.
Starten Sie die Java Shell mit dem Befehl jshell --enable-preview in der Konsole.
Den gültigen Java-Code können Sie direkt in der Java Shell eingeben oder über /edit als Ganzes bearbeiten.
Sie beenden die Java Shell mit dem Befehl /exit.
Die Java Shell eignet sich insbesondere für das Ausprobieren von Code-Schnipseln und das Testen von Methoden.
# jshell --enable-preview
| Welcome to JShell -- Version 23
| For an introduction type: /help intro
jshell> var x = "X";
x ==> "X"
jshell> x + "Y"
$2 ==> "XY"
jshell> $2.length()
$3 ==> 2
Rechnen auf der Konsole
Verwenden Sie die JShell als Taschenrechner und lösen Sie die folgenden Aufgaben in der angegebenen Reihenfolge jeweils mit Hilfe von einer Formel:
Berechnen Sie, wie viele Sekunden ein Schaltjahr hat.
Sie nehmen einen Kredit über 47865 € auf und zahlen monatlich 3,6% Zinsen. Wie viele Zinsen haben Sie nach 5 Jahren bezahlt?
Ein Bauer hat 120 Äpfel. Er möchte die Äpfel gleichmäßig auf 4 Körbe verteilen. Nachdem er die Äpfel aufgeteilt hat, isst er 5 Äpfel aus jedem Korb. Wie viele Äpfel hat er noch?
Nehmen Sie an, dass weltweit jeden Tag 1 500 000 000 Plastikflaschen produziert werden. Wie viele Flaschen werden in einem Jahr produziert, wenn das Jahr 365 Tage hat, aber an den Wochenenden nicht produziert werden würde (gehen Sie von 52 Wochenenden aus)?
Zum Starten der JShell müssen Sie die Konsole (ein Terminal) öffnen und jshell eingeben.
Hinweis
In Programmiersprachen wird generell die englische Schreibweise für Zahlen verwendet. D. h. Sie müssen das Dezimalkomma durch einen Punkt ersetzen.)
Die Division wird in (den meisten) Programmiersprachen mit dem Operator / durchgeführt.
Die Multiplikation wird in (den meisten) Programmiersprachen mit dem Operator * durchgeführt.
Sie können Klammern (( und )) so verwenden, wie Sie es von der Mathematik gewohnt sind.
Sie können große Zahlen mit einem Unterstrich (_) formatieren, um die Lesbarkeit zu erhöhen: z. B. 1_500_000_000
.
Um die erlaubten Werte von Parametern, Variablen und Rückgabewerten genauer spezifizieren zu können, werden Datentypen verwendet.
Java stellt hierzu primitive Datentypen, Aufzählungen (enum
), Klassen und Interfaces zur Verfügung
Ein primitiver Datentyp ist z. B. int
(d. h. integer bzw. Ganzzahl)
Dieser Datentyp legt fest, dass ein Wert eine Ganzzahl mit dem Wertebereich: \([-2147483648, 2147483647]\)
Art |
Datentyp |
Beispiel |
---|---|---|
Ganzzahlen |
|
|
Fließkommazahlen |
|
|
Zeichen |
|
|
Wahrheitswerte |
|
|
Bitte beachten Sie, dass in Code für Zahlen immer die Englische Schreibweise verwendet wird. D. h. das Dezimalkomma wird durch einen Punkt ersetzt.
Java kennt neben den primitiven Datentypen auch noch Arrays, Aufzählungen (enum
) sowie Klassen und Interfaces. Diese werden wir später behandeln.
Ganzzahlige Werte werden im Speicher als Binärzahlen gespeichert; d. h. als Folge von Nullen und Einsen.
Um verschieden große Werte zu speichern, stellen Programmiersprachen ganzzahlige Werte mit einer unterschiedlichen Zahl von Bits dar.
Zahlen werden immer mit 8 Bit (1 Byte), 16 Bit (2 Byte), 32 (4 Byte) oder 64 Bit (8 Byte) gespeichert.
Hinweis
In Java werden Zahlen immer vorzeichenbehaftet gespeichert. D. h. ein Bit wird für das Vorzeichen verwendet; auch wenn es nicht immer benötigt wird.
Umrechnung Binär-Dezimal
Binär |
Dezimal |
---|---|
|
+0 |
|
+1 |
... |
... |
|
+127 |
|
-128 |
... |
... |
|
-1 |
Datentyp |
Genauigkeit (in Bit) |
Wertebereich |
Anzahl Werte |
---|---|---|---|
|
8 |
-128 bis 127 |
\(2^8\) |
|
16 |
-32768 bis 32767 |
\(2^{16}\) |
|
32 |
-2147483648 bis 2147483647 |
\(2^{32}\) |
|
64 |
-922337022036854775808 bis 922337022036854775807 |
\(2^{64}\) |
Die Größenwahl für long und int ist teilweise historisch bedingt. Auf gängigen Prozessoren sind jedoch 64 Bit und 32 Bit die natürlichen Größen für Ganzzahlen und können effizient verarbeitet werden.
Gleitkommazahlen werden in Java nach Norm IEEE 754 (Seit Java 15 Version 2019) durch die Mantisse \(m\) und den Exponent \(e\) dargestellt: \(z = m \times 2^e\).
Für das Vorzeichen wird das erste Bit verwendet, für Mantisse und Exponent werden zusammen 31- (bei float
) bzw. 63-Bit (bei double
) verwendet.
Die Mantisse und der Exponent sind vorzeichenbehaftete Ganzzahlen.
Beispiel (vereinfacht)
\(7 \times 2^{-1} = { 7 \over 2 } = 3.5\)
\(-7 \times 2^{-1} = { -7 \over 2 } = -3.5\)
\(7 \times 2^{-3} = { 7 \over 8 } = 1.125\)
\(7 \times 2^{0} = { 7 \over 1 } = 7\)
Datentyp |
Genauigkeit |
Mantisse |
Exponent |
Wertebereich |
---|---|---|---|---|
|
32 |
23 |
8 |
ca. \(-3.4*10^{38}\; \text{bis}\; 3.4 \times 10^{38}\) |
|
64 |
52 |
11 |
ca. \(-1.8*10^{308}\; \text{bis}\; 1.8 \times 10^{308}\) |
Ganzzahlen \(< 2^{24}\) können bei Verwendung des Datentyps float
exakt dargestellt werden; bei double
sind es Ganzzahlen \(< 2^{53}\).
In beiden Fällen gibt es noch die Möglichkeit +/- Unendlich und NaN (Not a Number) zu repräsentieren.
Warnung
Bei Berechnungen mit Gleitkommazahlen treten Rundungsfehler auf, da nicht alle Werte in beliebiger Genauigkeit dargestellt werden können
Beispiel: Der Wert 0.123456789f (float) wird durch die Darstellung mit Mantisse und Exponent (\(m \times 2^e\)) zu 0.12345679.
Gleitkommazahlen sind somit nicht für betriebswirtschaftliche Anwendungen geeignet.
Gleitkommazahlen sind z. B. für wissenschaftliche Anwendungen geeignet.
Für betriebswirtschaftliche Anwendungen gibt es den Datentyp BigDecimal
. Dieser ist aber kein primitiver Datentyp und wird später behandelt.
einzelne Zeichen (z. B. 'a
') werden in Java mit dem Datentyp char
dargestellt
ein char
ist (intern) eine vorzeichenlose Ganzzahl mit 16 Bit (d. h. eine Zahl im Bereich \([0,65536]\)), die den Unicode-Wert des Zeichens repräsentiert
Alle gängigen (westeuropäischen) Zeichen können mit einem char
dargestellt werden.
Warnung
Seit Java eingeführt wurde, wurde der Unicode Standard mehrfach weiterentwickelt und heute gibt es Zeichen, die bis zu 32 Bit benötigen. Diese können mit nur einem char
nicht dargestellt werden und benötigen ggf. zwei char
s.
Für Zeichenketten (z. B. "Hello World") existiert ein nicht-primitiver Datentyp String
.
Unicode Zeichen und char
s
Hinweise:
- 0x1F60E ist der Unicode Codepoint von 😎 und Character.toChars(<Wert>)
rechnet den Wert um.
- In Java ist die Länge (<String>.length()
) einer Zeichenkette (String) die Anzahl der benötigten char
s und entspricht somit nicht notwendigerweise der Anzahl der (sichtbaren) Zeichen.
1jshell> var smiley = Character.toChars(0x1F60E)
2smiley ==> char[2] { '?', '?' }
34
jshell> var s = new String(smiley)
5s ==> "😎"
67
jshell> s.length()
8$1 ==> 2
910
jshell> s.getBytes(StandardCharsets.UTF_8)
11$2 ==> byte[4] { -16, -97, -104, -114 }
1213
jshell> s.codePointCount(0,s.length())
14$3 ==> 1
die Wahrheitswerte wahr (true
) und falsch (false
) werden in Java mit dem Datentyp boolean
dargestellt
häufigste (explizite) Verwendung ist das Speichern des Ergebnisses einer Bedingungsüberprüfung
(Wahrheitswerte sind zentral für Bedingungsüberprüfungen und Schleifen, werden dort aber selten explizit gespeichert; z. B. beim Test von n auf 0 im Algorithmus für die Berechnung der Fakultät.)
Die (meist verlustfreie,) implizite Konvertierung von Datentypen ist nur in eine Richtung möglich:
( (byte → short) | char ) → int → long → float → double
Konvertierungen in die andere Richtung sind immer explizit anzugeben, da es zu Informationsverlust kommen kann
Beispiel: int
zu byte
(Wertebereich \([-128,127]\))
Bei der Konvertierung von int
zu byte
werden die höherwertigen Bits (9 bis 32) einfach abgeschnitten.
(byte) 128 ⇒ -128
(byte) 255 ⇒ -1
(byte) 256 ⇒ 0
Beispiel für die verlustbehaftete implizite Konvertierung
jshell> long l = Long.MAX_VALUE - 1;
l ==> 9223372036854775806
jshell> float f = l
f ==> 9.223372E18
jshell> f == l
$1 ==> true // Warum ?
jshell> ((long) f) == l
$2 ==> false
jshell> ((long) f)
$3 ==> 9223372036854775807 // == Long.MAX_VALUE
Wahrheitswerte können nicht konvertiert werden.
Literale stellen konstante Werte eines bestimmten Datentyps dar:
Datentyp |
Literal (Beispiele) |
---|---|
|
Dezimal: 127 ; Hexadezimal: 0xcafebabe[3] ; Oktal: 010 ; Binär: 0b1010 |
|
123_456_789l oder 123456789L ("_" dient nur der besseren Lesbarkeit) |
|
0.123456789f oder 0.123456789F |
|
0.123456789 oder 0.123456789d oder 0.123456789D |
|
'a' (Zeichen-Darstellung) oder 97 (Zahlen-Darstellung) oder '\u0061' (Unicode-Darstellung) oder Sonderzeichen (siehe nächste Folie) |
|
"Hallo" oder """ Text-block""" |
|
true oder false |
0xcafebabe ist der Header aller kompilierten Java-Klassen-Dateien.
Textblöcke werde seit Java 15 unterstützt.
Mittels: -Xlint:text-blocks
können Sie sich warnen lassen, wenn die Textblöcke potentiell nicht korrekt formatiert sind.
Datentyp |
Literal (Beispiele) |
---|---|
\' |
Einfaches Hochkomma |
\" |
Doppeltes Hochkomma |
\ \ |
Backslash |
\b |
Rückschrittaste (backspace) |
\f |
Seitenvorschub (form feed) |
\n |
Zeilenschaltung (line feed) |
\t |
Tabulator |
\r |
Wagenrücklauf |
Variablen stellen einen logischen Bezeichner für einen Wert eines bestimmten Datentyps dar.
Variablen müssen erst deklariert werden. Danach können sie weiter initialisiert werden, wenn der Standardwert nicht ausreicht.
- Deklaration:
Variablennamen und Datentyp werden festgelegt
- Initialisierung (optional):
Variablen werden mit einem bestimmten Wert versehen
der Wert einer Variablen kann jederzeit geändert werden
Beispieldeklaration und -initialisierung
void main() {
// Deklaration (Datentyp muss konkret angegeben werden)
int alter;
// Deklaration und Initialisierung inkl. Datentyp (Standarfall)
String name = "Asta Mueller";
// vereinfachte Deklaration mittels var und Initialisierung (seit Java 10)
// (Datentyp wird automatisch erkannt)
var geburtsOrt = "Berlin";
var wohnort = "Schönau";
var geschlecht = 'd';
alter = 25; // späte Initialisierung
println(name + "(" + geschlecht + "), " + alter + " Jahre, aus " + wohnort);
}
Konstanten sind Variablen, die nach der Initialisierung nicht mehr verändert werden können
Konstanten werden in Java mit dem Schlüsselwort final
deklariert
Es wird überprüft, dass keine weitere Zuweisung erfolgt
Konvention: Konstanten werden in Großbuchstaben geschrieben
Beispieldeklaration und -initialisierung
void main() {
// Deklaration und Initialisierung inkl. Datentyp (Standarfall)
final String NAME = "Asta Mueller";
// vereinfachte Deklaration mittels var und Initialisierung (seit Java 10)
// (Datentyp wird automatisch erkannt)
final var WOHNORT = "Schönau";
final var GESCHLECHT = 'd';
println(NAME + "(" + GESCHLECHT + "), " + " Jahre, aus " + WOHNORT);
// name = "Berta"; // error: cannot assign a value to final variable name
}
Bezeichner sind Namen für Variablen, Konstanten, Methoden, Klassen, Interfaces, Enums, etc.
Erstes Zeichen: Buchstabe, Unterstrich (_) oder Dollarzeichen ($);
Folgende Zeichen: Buchstaben, Ziffern, Unterstrich oder Dollarzeichen
Groß- und Kleinschreibung wird unterschieden
Schlüsselworte (z. B. var
, int
, etc.) dürfen nicht als Bezeichner verwendet werden
Konvention:
Variablen (z. B.
aktuellerHerzschlag
) und Methoden (z. B.println
) verwenden lowerCamelCaseKonstanten verwenden UPPER_CASE und Unterstriche (z. B.
GEWICHT_BEI_GEBURT
)Klassen, Interfaces und Enums verwenden UpperCamelCase (z. B.
BigDecimal
)
In Java ist es unüblich, das Dollarzeichen ($) in eigenem Code zu verwenden und es wird in der Regel nur von der JVM (der Java Virtual Machine; d. h. der Ausführungsumgebung) verwendet.
Ein Unterstrich am Anfang des Bezeichners sollte ebenfalls vermieden werden. Ganz insbesondere ist darauf zu verzichten den Unterstrich als alleinigen Variablennamen zu verwenden, da der reine Unterstrich seit Java 22 für unbenannte Variablen verwendet wird und dies die Migration von altem Code erschwert.
Welche der folgenden Bezeichner sind (a) ungültig, (b) gültig aber sollten dennoch nicht verwendet werden oder (c) gültig und entsprechen den Konventionen?
Bezeichner
1var 1a = ...
2var 1_a = ...
3var _1a = ...
4var a1 = ...
5int i;
6int _i;
7float $$f;
8final float E = ...;
9String Wohnort;
10String ortDerGeburt;
11void BucheFlug(){...}
12class FlugBuchungen{...}
Hinweis
Für diese Aufgabe können Sie sowohl die Java Shell verwenden als auch Ihren Code in eine Datei schreiben. Denken Sie in diesem Fall daran, dass der Code in einer Methode main
stehen muss (void main(){ <IHRE CODE> }
).
Grundlegende Datentypen
Deklarieren und initialisieren Sie eine Variable x mit dem Ganzzahlwert 42.
Welche Datentypen können Sie verwenden, wenn eine präzise Darstellung des Wertes notwendig ist?
Welcher Datentyp wird verwendet, wenn Sie keinen Typ angeben (d. h. wenn Sie var
schreiben bzw. anders ausgedrückt welchen Typ hat das Literal 42)?
Weisen Sie den Wert der Variable x einer Variable f vom Typ float
zu.
Ändern Sie den Wert der Variablen x. Welche Auswirkungen hat das auf die Variable f vom Typ float
?
Deklarieren und initialisieren Sie die Konstante π (Wert 3.14159265359).
Berechnungen erfolgen über Ausdrücke, die sich aus Variablen, Konstanten, Literalen, Methodenaufrufen und Operatoren zusammensetzen.
Jeder Ausdruck hat ein Ergebnis (d. h. Rückgabewert).
Beispiel: (age + 1) addiert zwei Werte und liefert das Ergebnis der Addition zurück.
Einfache Ausdrücke sind Variablen, Konstanten, Literale und Methodenaufrufe.
Komplexe Ausdrücke werden aus einfachen Ausdrücken und Operatoren (z. B. +, -, *, /, %, >, <, >=, <=) zusammengesetzt
Ergebnisse von Ausdrücken können insbesondere Variablen zugewiesen werden (z.B. int newAge = age + 1
oder var isAdult = age >= 18
)
Ausdrücke, die einen Wahrheitswerte ergeben können zusätzlich in Bedingungen (z. B. if(age + 5 >= 18) ...
) verwendet werden.
void main() {
String s = readln("Enter your age: ");
int age = Integer.parseInt(s);
if (age >= 18) {
println("You are an adult.");
} else {
println("You are a minor.");
}
var yearsUntil100 = 100-age;
println("You will be 100 in " + yearsUntil100 + " years.");
}
Binäre/Zweistellige Operatoren (Binary Operators)
Addition
Unäre/Einstellige Operatoren (Unary Operators)
Negation
Fakultät
Operatoren sind spezielle Zeichen, die auf Variablen, Konstanten und Literale angewendet werden, um Ausdrücke zu bilden.
Die Auswertungsreihenfolge wird durch die Priorität der Operatoren bestimmt.
(Wie aus der Schulmathematik bekannt gilt auch in Java: * oder / vor + und -.)
Runde Klammern können verwendet werden, um eine bestimmt Auswertungsreihenfolge zu erzwingen bzw. dienen zur Strukturierung
Es gibt Operatoren, die auf eine, zwei oder drei Operanden angewendet werden: diese nennt man dann ein-, zwei- oder dreistellige Operatoren.
Für einstellige Operatoren wird die Präfix- oder Postfix-Notation (z.B. ++a
oder a++
) verwendet,
Für mehrstellige Operatoren wird die Infix-Notation (z.B. a + b
) verwendet
Arithmetische Operatoren (auf numerische Datentypen)
Vergleichsoperatoren
Logische Operatoren (auf boolean Datentypen)
Bedingungsoperatoren
Bitoperatoren (auf ganzzahligen Datentypen)
Zuweisungs- und Verbundoperatoren (auf alle Datentypen)
Konkatenationsoperator (String)
Explizite Typkonvertierung
Einige Operatoren sind nur auf bestimmten Datentypen anwendbar. So sind Vergleichsoperatoren wie <= oder >= nur auf numerische Datentypen anwendbar, aber == und != auf allen Typen. Es gilt immer, dass die linke und die rechte Seite Typkompatibel sein müssen; mit anderen Worten wir können nur Dinge vergleichen, die den gleichen Typ haben oder für die eine automatische Typumwandlung möglich ist. Ein Vergleich von einem String und einer Zahl ist z. B. nicht möglich.
Beispiel für unzulässigen Vergleich:
jshell> "s" == 1
| Error:
| bad operand types for binary operator '=='
| first type: java.lang.String
| second type: int
| "s" == 1
Hinweis
Wenn Sie die folgenden Codeschnipsel (Snippets) in der Java Shell (jshell) ausführen möchten, dann müssen sie noch die Methoden println
und readln
definieren: void println(Object o) { System.out.println(o); }
und String readln(String s) { return System.console().readln(s); }
.
Alternativ können Sie den unten verlinkten Code direkt in die JShell laden:
jshell --enable-preview <DATEINAME>
Alternative können Sie ein Java Script schreiben (inkl. main Methode). In diesem Fall sind die beiden Methoden direkt verfügbar und müssen nicht extra deklariert werden.
Ich empfehle Ihnen, die Beispiele händisch einzugeben, dann lernen Sie mehr!
Operator |
Anwendung |
Bedeutung |
---|---|---|
+ |
x + y |
Summe von x und y (Additions-Operator) |
- |
x - y |
Differenz von x und y (Subtraktions-Operator) |
* |
x * y |
Produkt von x und y (Multiplikations-Operator) |
/ |
x / y |
Quotient von x und y (Divisions-Operator) |
% |
x % y |
Rest der ganzzahligen Division von x und y (Modulo-Operator) |
JShell-Beispiel: ArithmetischeOperatoren.jshell.java
1// Zweistellige Operatoren
2int x = 3;
3int y = 5;
4println( x + y );
5println( x * y );
6int z = y / x;
7println( z );
8int result = z + z;
9println( result );
Zweistellige Operatoren - welche Werte werden ausgegeben?
Andere Sprachen (z. B. JavaScript oder Python) haben häufig noch ** für die Potenzierung. Dies ist in Java über Math.pow möglich.
Operator |
Anwendung |
Bedeutung |
---|---|---|
+ |
+x |
Positiver Wert von x |
- |
-x |
Negativer Wert von x |
(Präfix) ++ |
++x |
Prä-inkrement: Gleichbedeutend mit \(\{ x_{neu}=x_{alt}+1; x_{neu} \}\) |
++ (Postfix) |
x++ |
Post-inkrement: Gleichbedeutend mit \(\{ x_{neu}=x_{alt}+1; x_{alt} \}\) |
(Präfix) -- |
--x |
Prä-dekrement: Gleichbedeutend mit \(\{ x_{neu}=x_{alt}-1; x_{neu} \}\) |
-- (Postfix) |
x-- |
Post-dekrement: Gleichbedeutend mit \(\{ x_{neu}=x_{alt}-1; x_{alt} \}\) |
JShell-Beispiel: ArithmetischeOperatoren.jshell.java
1// Einstellige Operatoren
2int a = 5;
3println( ++a );
4println( a++ );
5println( -a );
Einstellige Operatoren - welche Werte werden ausgegeben?
Operator |
Anwendung |
Bedeutung |
---|---|---|
== |
x == y |
Überprüft, ob die Werte von x und y gleich sind |
!= |
x != y |
Überprüft, ob der Werte von x und y ungleich sind |
< |
x < y |
Überprüft, ob der Wert von x kleiner dem Wert von y ist |
<= |
x <= y |
Überprüft, ob der Wert von x kleiner oder gleich dem Wert von y ist |
> |
x > y |
Überprüft, ob der Wert von x größer dem Wert von y ist |
>= |
x >= y |
Überprüft, ob der Wert von x größer oder gleich dem Wert von y ist |
JShell-Beispiel: Vergleichsoperatoren.jshell.java
1// String-Vergleiche
2println("Michael" == "Michael");
3println("Michael" == "michael");
4println("Michael" != "michael");
56
// Vergleiche von numerischen Werten
7println(1 >= 1);
8println(2 >= 1d);
9println(2d >= 3l);
1011
// UNGÜLTIG: "Michael" == 1
Einstellige Operatoren - welche Werte werden ausgegeben?
Operator |
Anwendung |
Bedeutung |
---|---|---|
! |
!x |
Negation (Aus true wird false und umgekehrt) |
& |
x & y |
Logisches UND (AND) |
&& |
x && y |
Bedingtes logisches UND (AND Short-circuit Evaluation) |
| |
x | y |
Logisches ODER (OR) |
|| |
x || y |
Bedingtes logisches ODER (OR Short-circuit Evaluation) |
^ |
x ^ y |
Logisches ENTWEDER-ODER (XOR exclusive OR) |
Wahrheitstabelle
x |
y |
!x |
x & y oder x && y |
x | y oder x || y |
x ^ y |
true |
true |
false |
true |
true |
false |
true |
false |
false |
false |
true |
true |
false |
true |
true |
false |
true |
true |
false |
false |
true |
false |
false |
false |
JShell-Beispiel: LogischeOperatoren.jshell.java
1int x = 5;
2int y = 7;
3int n = 0;
45
println(x == 5 && y == 7);
6println(n != 0 && y/n == 1);
7println(n != 0 & y/n == 1); // ?!
8println(x == 5 && y/x >= 1);
910
println(x == 5 || y/x >= 0);
11println(x == 5 || y/n >= 0);
12println(y/n >= 0 || x == 5); // ?!
Logische Operatoren - welche Werte werden ausgegeben?
Der Unterschied zwischen & und && ist, dass && nur den rechten Operanden auswertet, wenn der linke Operand true ist.
Der Unterschied zwischen | und || ist, dass || nur den rechten Operanden auswertet, wenn der linke Operand false ist.
Mit anderen Worten bei && und || wird der Ausdruck nur so weit ausgewertet, wie nötig ist, um das Ergebnis des Ausdrucks als Ganzes zu bestimmen.
Vergleichsoperatoren
Lesen Sie zwei Zahlen von der Console ein (siehe Von der Konsole lesen) und vergleichen Sie diese auf Gleichheit. Speichern Sie das Ergebnis in einer Variable und geben Sie das Ergebnis danach auf der Konsole aus.
Zum Konvertieren der eingelesenen Zeichenketten in Zahlen verwenden Sie die Methode Integer.parseInt(<EINGABE>)
. Sie können hier den eingelesen String direkt an die Methode übergeben oder vorher in einer Variable speichern.
Denken Sie daran, dass Ihr Code in die main Methode gehört:
void main() {
// Ihr Code
}
Schreiben Sie ein vollständiges Java Script, dass Sie mit dem Java Interpreter (java --enable-preview <JAVA-DATEI>) ausführen können.
Der Bedingungsoperator:
<Bedingungsausdruck \(c\)> ?<auszuwertender Ausdruck \(a_{(c\,wahr)}\) falls \(c\) wahr >:<auszuwertender Ausdruck \(a_{(c\,falsch)}\) falls \(c\) falsch/unwahr>
liefert in Abhängigkeit eines Ausdrucks c (der einen Wahrheitswert liefert) das Ergebnis des ersten Ausdrucks oder des zweiten Ausdrucks zurück.
\(c\; ?\; a_{(c\,wahr)}\; :\; a_{(c\,falsch)}\)
Beide Ausdrücke \(a_{(c\,wahr)}\) und \(a_{(c\,falsch)}\) müssen entweder numerische Werte oder boolean Werte oder Instanzen einer Klasse zurück liefern (d. h. Werte die implizit ineinander konvertiert werden dürfen)
Von den beiden Ausdrücken wird nur ein Ausdruck ausgewertet.
Beispiele
int n = 0;
n == 0 ? 1 : 2
Verschachtelung ist möglich aber nicht empfehlenswert:
int alter = Integer.parseInt(readln("Wie alt sind Sie?"));
alter < 18 ?
"jugendlicher" :
alter < 65 ?
"erwachsener" :
"senior";
Bitoperatoren (>>, <<, ...) arbeiten auf der binären Darstellung der numerischen, primitiven Datentypen für Ganzzahlen.
Bitoperationen werden häufig für spezielle Algorithmen verwendet, um die gleiche Operation auf mehreren Daten (den Bits) gleichzeitig anzuwenden (1 CPU Zyklus). Ein Beispiel ist das Ver-/Entschlüsseln von Daten (insbesondere mit XOR).
Bestimmte mathematische Operationen (z. B. Division durch \(2^x\)) können durch Bitoperationen ersetzt werden, die effizienter sind (z. B. 16 / 4 == 16 >> 2
).
Operator |
Anwendung |
Bedeutung |
---|---|---|
~ |
~x |
Bitweise-Negation |
& |
x & y |
Bitweise UND |
| |
x | y |
Bitweise ODER |
^ |
x ^ y |
Bitweise ENTWEDER-ODER |
<< |
x << y |
Bits von x werden um y Positionen nach links verschoben und von rechts mit 0 aufgefüllt |
>> |
x >> y |
Bits von x werden um y Positionen nach rechts verschoben und von links mit dem höchsten Bit aufgefüllt |
>>> |
x >>> y |
Bits von x werden um y Positionen nach rechts verschoben und von links mit 0 aufgefüllt |
Bits verschieben (shiften) um eine bestimmte Anzahl von Positionen:
jshell> Integer.toBinaryString(Integer.MIN_VALUE)
$1 ==> "10000000000000000000000000000000"
jshell> Integer.toBinaryString(Integer.MIN_VALUE >> 31)
$2 ==> "11111111111111111111111111111111"
jshell> Integer.toBinaryString(Integer.MIN_VALUE >>> 31)
$3 ==> "1"
Verschlüsselung mit XOR (EncryptionWithXOR.jshell.java):
final var key = new java.util.Random().nextInt();
Integer.toBinaryString(key); // ==> "1001101011000011100110101001110"
final var income = 13423;
Integer.toBinaryString(income); // ==> "11010001101111"
// Verschlüsselung von "income" mit "key" mit Hilfe von XOR:
final var encryptedIncome = income ^ key;
Integer.toBinaryString(encryptedIncome); // ==> "1001101011000011111100100100001"
Warnung
Die dargestellte Verschlüsselung mit XOR ist die Grundlage aller modernen Verschlüsselungsalgorithmen, aber es gibt sehr viel zu beachten, um eine sichere Verschlüsselung zu gewährleisten.
Zuweisungs- und Verbundoperatoren weisen einer Variablen einen neuen Wert zu (z. B. int newAge = age + 1;
).
Die Variable steht auf der linken Seite des Operators.
Der Ausdruck zur Berechnung des neuen Wertes ist durch den Operator selbst und den Ausdruck auf der rechten Seite festgelegt.
Das Ergebnis des kompletten Ausdruckes ist der zugewiesene Wert mit dem entsprechenden Datentyp.
Standardbeispiele:
jshell> int age = 1;
age ==> 1
jshell> age = age + 1;
age ==> 2
jshell> age += 1;
age ==> 3
Folgendes wäre auch erlaubt, aber nicht empfehlenswert, da schwer(er) zu lesen:
jshell> var newAge = age = age + 1;
newAge ==> 4
jshell> var newAge = age += 1;
newAge ==> 5
Operator |
Bedeutung |
---|---|
x = y |
Zuweisung des Wertes von y an x |
x <Operator>= y |
Zuweisung des Wertes von x <Operator> y an x |
Operatoren: +, -, *, /, %, &, |, ^, <<, >>, >>>
Zum Beispiel: x <<= y
ist gleichbedeutend mit x = x << y
.
Literale, Variablen, Konstanten vom Datentyp String werden durch den Konkatenationsoperator + zu einem neuen String-Wert verkettet.
jshell> final String name = "Max";
name ==> "Max"
jshell> String greeting = "Hallo " + name + "!";
greeting ==> "Hallo Max!"
Bei Zuweisungen und arithmetischen Operationen werden die Datentypen von Operanden unter bestimmten Umständen implizit konvertiert.
Bei arithmetischen Operationen erfolgt eine Konvertierung in den nächst größeren Datentyp der beteiligten Operanden bzgl. int
, long
, float
, double
.
Bei Operationen auf primitiven, ganzzahligen Datentypen wandelt der Compiler die beteiligten Operanden mindestens in int
um.
Bei Zuweisungen wird das Ergebnis des Ausdruckes auf der rechten Seite in den Datentyp der Variablen auf der linken Seite konvertiert gemäß der Regeln (Konvertierung von Datentypen).
⚠️ Die Typkonvertierung erfolgt unabhängig von den konkreten Werten der Operanden.
jshell> byte b = 13;
short s = Short.MAX_VALUE;
float f = b + s;
b ==> 13
s ==> 32767
f ==> 32780.0
jshell> int r = Integer.MAX_VALUE + Integer.MAX_VALUE;
r ==> -2
Warnung
Hier erfolgt keine Überlaufprüfung und demzufolge auch keine (implizite) Konvertierung (z. B. in Long).
Hinweis
Bei der Addition von Integer.MAX_VALUE
und Integer.MAX_VALUE
wird der Wert -2
zurückgegeben, da der Wert Integer.MAX_VALUE + 1
den Wert Integer.MIN_VALUE
ergibt (wir haben einen Überlauf (Overflow)).
Integer.MAX_VALUE + Integer.MAX_VALUE
entspricht also Integer.MIN_VALUE + (Integer.MAX_VALUE - 1)
.
jshell> short s = Short.MAX_VALUE + Short.MAX_VALUE;
| Error:
| incompatible types: possible lossy conversion from int to short
| short s = Short.MAX_VALUE + Short.MAX_VALUE;
Das Ergebnis eines Ausdruckes kann durch explizite Typkonvertierung in einen anderen primitiven Datentyp umgewandelt werden.
Bei primitiven Datentypen erlaubt für numerische Datentypen.
Wird ein ganzzahliges Ergebnis in einen kleineren ganzzahligen Datentyp konvertiert, dann werden die führenden Bits abgeschnitten.
Nachkommastellen gehen bei der Konvertierung von Gleitkommazahlen in Ganzzahlen verloren
Bei Konvertierung von double
in float
kommt es ebenfalls zu einem Genauigkeitsverlust in der Darstellung (durch Abschneiden der Bits in Mantisse und Exponent)
Standardfälle
jshell> int i = 42;
i ==> 42
jshell> byte b = (byte) i;
b ==> 42
Sonderfälle
jshell> (byte) 128 ;
$1 ==> -128
jshell> (byte) 256 ; // Integer.numberOfTrailingZeros(256) == 8
$2 ==> 0
Unter-/Überschreitet das Ergebnis eines Ausdruckes den minimalen/maximalen Wert des resultierenden Datentyps, erfolgt ein Unter-/Überlauf. (Overflow/Underflow)
Bei einem Unterlauf bzw. Überlauf werden bei Ganzzahlen die nicht mehr darstellbaren höheren Bits abgeschnitten.
Bei Fließkommazahlen werden die Konstanten: Float.NEGATIVE_INFINITY
und Float.POSITIVE_INFINITY
bzw. Double.NEGATIVE_INFINITY
und Double.POSITIVE_INFINITY
verwendet.
Integer.toBinaryString(Integer.MIN_VALUE) // "10000000000000000000000000000000"
Integer.toBinaryString(Integer.MIN_VALUE - 1) //"01111111111111111111111111111111"
Long.toBinaryString(Integer.MIN_VALUE -1l)
// "1111111111111111111111111111111101111111111111111111111111111111"
In der Praxis wird häufig der Begriff Overflow verwendet, wenn bei einer Berechnung der Wertebereich eines Datentyps nicht ausreicht, um das Ergebnis zu speichern. D. h. die Unterscheidung zwischen Über- und Unterlauf ist nicht immer eindeutig.
Bei Double erfolgt der Überlauf erst, wenn man eine Zahl auf Double.MAX_VALUE
addiert, die mehr als 292 Stellen vor dem Komma hat.
jshell> Double.MAX_VALUE + 1
$0 ==> 1.7976931348623157E308
jshell> Double.MAX_VALUE + 1999999999999999999999999
9999999999999999999999999999999999999999999999999999
9999999999999999999999999999999999999999999999999999
9999999999999999999999999999999999999999999999999999
9999999999999999999999999999999999999999999999999999
9999999999999999999999999999999999999999999999999999
9999999d // Eins gefolgt von 291 Neunen(!)
$1 ==> 1.7976931348623157E308 // 16 Nachkommastellen
jshell> Double.MAX_VALUE + 1000000000000000000000000
0000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000
00000000d // 1 gefolgt von 292 Nullen(!)
$2 ==> Infinity
Die Auswertungsreihenfolge von komplexen Ausdrücken mit mehreren Operatoren wird durch die Priorität der Operatoren bestimmt.[4]
Kommen in einem Ausdruck mehrere Operatoren mit gleicher Priorität vor, dann wird der Ausdruck von links nach rechts ausgewertet.
Ausnahmen sind die Verbund- und Zuweisungsoperatoren die von rechts nach links bewertet werden.
Klammern haben die höchste Priorität und erzwingen die Auswertung des Ausdrucks in den Klammern zuerst. Klammern dienen aber (insbesondere) auch der Strukturierung von Ausdrücken.
Die Regeln sind vergleichbar mit der Schulmathematik: Punkt-vor-Strich-Rechnung.
Operatoren |
Beschreibung |
Priorität |
---|---|---|
=, +=, -=, ... |
Zuweisungs- und Verbundoperatoren |
1 (niedrigste) |
?: |
Bedingungsoperator |
2 |
|| |
Bedingt logisches ODER |
3 |
&& |
Bedingt logisches UND |
4 |
| |
Logisches/Bitweises ODER |
5 |
^ |
Logisches/Bitweises ENTWEDER-ODER |
6 |
& |
Logisches/Bitweises UND |
7 |
==, != |
Vergleich: Gleich, Ungleich |
8 |
<, <=, >, >= |
Vergleich: Kleiner (oder Gleich), Größer (oder Gleich) |
9 |
<<, >>, >>> |
Bitweise Schiebeoperatoren |
10 |
+, - |
Addition, Subtraktion, String-Konkatentation |
11 |
*, /, % |
Multiplikation, Division, Rest |
12 |
++, --, +, - (Vorzeichen), ~, !, (cast) |
Einstellige Operatoren |
13 (höchste) |
Auswertung von Ausdrücken
Sind die folgenden Ausdrücke (a) gültig und wie ist (b) ggf. das Ergebnis der folgenden Ausdrücke und (c) welchen Wert haben die Variablen nach der Auswertung (der neue Wert wird dann für den nachfolgenden Ausdruck verwendet)?
Initiale Belegung der Variablen: int x = 4, y = 2, z = 3;
.
1 x + y * z / x
2 ( x + - (float) y * 2 ) / x == ( x + ( ( (float) -y ) * 2 ) )/ x
3 x + ++y * z++ % x
4 x < 5 && --y <= 1 || z == 3
5 x << 2 * y >> 1
6 z & 1 % 2 == 0
7 (z & 1) % 2 == 0
Body-Mass-Index (BMI) berechnen mit Java Script
Lesen Sie das Gewicht in Kilogramm und die Größe in Metern von der Konsole ein und geben Sie den BMI auf der Konsole aus. Geben Sie auch aus, ob die Person Untergewicht, Normalgewicht oder Übergewicht hat. Falls die Person nicht das Normalgewicht hat, geben Sie auch an, wie viel Gewicht sie bis zum Normalgewicht zunehmen oder abnehmen muss. Berechnungsvorschrift: \(BMI = \frac{Gewicht}{Größe^2}\).
Beispielinteraktion:
Bitte geben Sie Ihr Gewicht in Kilogramm ein: 80
Bitte geben Sie Ihre Größe in Metern ein: 1.80
Ihr BMI beträgt 24.69
Untergewicht: nein
Normalgewicht: nein
Übergewicht: 5.897499999999994 kg bis Normalgewicht
Denken Sie daran, dass Ihr Code in die main Methode gehört:
void main() {
// Ihr Code
}
Denken Sie daran, dass Sie einen Zeichenkette (String) in eine Zahl umwandeln können, indem Sie die Methode Double.parseDouble(<String>)
für Fließkommazahlen verwenden oder Integer.parseInt(<String>)
für Ganzzahlen.
Schreiben Sie ein vollständiges Java Script, dass Sie mit dem Java Interpreter (java --enable-preview <JAVA-DATEI>) ausführen können.
Umrechnung von Sekunden
Schreiben Sie ein Java Script, dass die Anzahl von Sekunden in Stunden, Minuten und Sekunden umrechnet. Lesen Sie die Anzahl von Sekunden von der Konsole ein und geben Sie die Umrechnung auf der Konsole aus.
Beispielinteraktion:
Bitte geben Sie die Sekunden ein: 3455
0 Stunde(n), 57 Minute(n) und 35 Sekunde(n)
Variablen sind Speicherorte, die einen Wert enthalten.
Konstanten sind unveränderliche Werte, die an einem Speicherort gespeichert sind.
Literale sind konstante Werte, die direkt im Code stehen.
Operatoren haben eine Priorität und bestimmen die Auswertungsreihenfolge von Ausdrücken.
Ausdrücke sind Kombinationen von Variablen, Konstanten und Operatoren, die einen Wert ergeben.
Implizite Typkonvertierung erfolgen automatisch und führen meist zu keinem Verlust von Genauigkeit.
Eine Anweisung in einem Java-Programm stellt eine einzelne Vorschrift dar, die während der Abarbeitung des Programms auszuführen ist.
In Java-Programmen werden einzelne Anweisungen durch einen Semikolon ;
voneinander getrennt.
void main() {
int a = 1; // Variablendeklaration und Initialisierung
println("a = " + a); // Methodenaufruf (hier: println)
}
Programme setzen sich aus einer Abfolge von Anweisungen zusammen.
Die einfachste Anweisung ist die leere Anweisung: ;
.
Weitere Beispiele für Anweisungen sind Variablendeklarationen und Initialisierungen, Zuweisungsausdrücke, Schleifen, Methoden-Aufrufe.
Ein Block in einem Java-Programm ist eine Folge von Anweisungen, die durch geschweifte Klammern { ... } zusammengefasst werden.
Blöcke werden nicht durch einen Semikolon beendet.
void main() {
{ // Block von Anweisungen
int a = 1;
println("a = "+a);
}
}
Ein Block kann dort verwendet werden, wo auch eine Anweisung erlaubt ist.
Ein Block stellt ein Gültigkeitsbereich (scope) für Variablendeklarationen dar. Auf die entsprechenden Variablen kann nur von innerhalb des Blocks zugegriffen werden.
Leere Blöcke {}
sind erlaubt und Blöcke können verschachtelt werden.
// Deklaration und Initialisierung von Variablen
int age = 18 + 1;
char gender = 'm';
; // Leere Anweisung
// Block
{
boolean vegi = true;
gender = 'f';
System.out.println("vegi=" + vegi);
{} // leerer Block
}
// Methodenaufruf
println("age=" + age);
println("gender=" + gender);
/* println("vegi=" + vegi); => Error: cannot find symbol: variable vegi */
Bedingte Anweisungen und Ausdrücke in einem Java-Programm dienen dazu Anweisungen bzw. Blöcke nur dann auszuführen wenn eine logische Bedingung eintrifft.
Bedingte Anweisungen und Ausdrücke zählen zu den Befehlen zur Ablaufsteuerung.
Bedingte Anweisungen und Ausdrücke können in Java-Programmen mittels if
-Anweisungen, if
-/else
-Anweisung und switch
-Anweisungen/-Ausdrücken umgesetzt werden.
Der Bedingungs-Operator (<Ausdruck> ? <Ausdruck> : <Ausdruck>
) stellt in bestimmten Fällen eine Alternative zu den bedingten Anweisungen dar.
if
-AnweisungDie if
-Anweisung setzt sich zusammen aus dem Schlüsselwort if
, einem Prüf-Ausdruck in runden Klammern und einer Anweisung bzw. einem Block.
if(<Ausdruck>) <Anweisung> bzw. <Block>
1void main() {
2var age = Integer.parseInt(readln("Wie alt sind Sie?"));
3boolean adult = false;
45
if (age >= 18) { // if-Anweisung
6adult = true;
7}
89
println("adult=" + adult);
10}
1void main() {
2var age = Integer.parseInt(readln("Wie alt sind Sie?"));
3var adult = false;
4char status = 'c';
56
if (age >= 18) {
7adult = true;
8status = 'b';
9if (age >= 30 && readln("Geschlecht (m/w/d)?").charAt(0) == 'm')
10status = 'a';
11}
12println("adult=" + adult+ ", status=" + status);
13}
Der <Ausdruck>
muss einen Wert vom Datentyp boolean
zurückliefern
Die <Anweisung>
bzw. der <Block>
wird ausgeführt, wenn der Ausdruck true
zurück liefert
Ansonsten wird die nächste Anweisung nach der if
-Anweisung ausgeführt
if
-Anweisungen können verschachtelt werden (in der Anweisung bzw. im Block).
if
-else
-Anweisung1void main() {
2println("Anzahl der Tage in einem Monat");
34
var month = Integer.parseInt(readln("Welchen Monate haben wir(1-12)? "));
56
int days = 31;
7if (month == 2 && readln("Schaltjahr (j/n)? ").charAt(0) == 'j')
8days = 29;
9else if (month == 2)
10days = 28;
11else if (month == 4)
12days = 30;
13// ...
14println("days=" + days);
15}
1void main() {
2println("Anzahl der Tage in einem Monat");
34
var month = Integer.parseInt(readln("Welchen Monate haben wir(1-12)? "));
56
int days = 31;
7if (month == 2 && readln("Schaltjahr (j/n)? ").charAt(0) == 'j')
8days = 29;
9else // "nur" umformatiert
10if (month == 2)
11days = 28;
12else
13if (month == 4)
14days = 30;
15// else ...
16println("days=" + days);
17}
Die if
-Anweisung kann um einen else
-Zweig erweitert werden, der aus dem Schlüsselwort else
und einer Anweisung bzw. einem Block besteht.
if(<Ausdruck>) <Anweisung bzw. Block> else <Anweisung bzw. Block>
Die <Anweisung>
bzw. der <Block>
im else-Zweig wird ausgeführt, wenn der Ausdruck in der if
-Anweisung false
zurück liefert.
Im else
-Zweig kann wieder eine weitere if
-Anweisung verwendet werden (if
/ else-if
Kaskade).
Bei verschachtelten if
-Anweisungen gehört der else
-Zweig zur direkt vorhergehenden if
-Anweisung ohne else
-Zweig.
switch
-Anweisung/-Ausdruck (Grundlagen)Die switch
-Anweisung bzw. der switch
-Ausdruck setzt sich aus dem Schlüsselwort switch
, einem Prüf-Ausdruck in runden Klammern und einem oder mehreren case
-Blöcken zusammen.
switch(<Ausdruck>) <case-Block>* [<default-Block>]
Im Gegensatz zur if
-else
Anweisung wird hier nur ein <Ausdruck> ausgewertet für den mehrere Alternativen (case
-Blöcke) angegeben werden können.
Der default
-Zweig stellt eine Möglichkeit dar, die immer dann ausgeführt wird, wenn kein anderer case
-Block zutrifft
default: <Anweisungen>
case L :
case <Literal>: <Anweisungen>
.
Ein case
-Block setzt sich zusammen aus dem Schlüsselwort case
, einem oder mehreren Literal
en (konstanter Ergebniswert) und einer Abfolge von Anweisungen.
Die Anweisung in einem case :
-Block werden bis zur folgenden break
-Anweisung ausgeführt (fall-through).
Gibt es keine break
-Anweisung in einem case
-Block werden alle Anweisungen bis zum Ende der switch
-Anweisung ausgeführt.
1void main() {
2var month = Integer.parseInt(readln("Welchen Monate haben wir(1-12)? "));
3int days = 31;
4switch (month) { // vor Java 14!
5case 2:
6if (readln("Schaltjahr (j/n)? ").charAt(0) == 'j')
7days = 29;
8else
9days = 28;
10break;
11case 4:
12case 6: case 9: case 11: // <= possible, but unusual formatting
13days = 30;
14break;
15}
16println("Anzahl der Tage im Monat " + days);
17}
1void main() {
2var month = Integer.parseInt(readln("Welchen Monate haben wir(1-12)? "));
3int days = 31;
4switch (month) { // seit Java 14
5case 2:
6if (readln("Schaltjahr (j/n)? ").charAt(0) == 'j')
7days = 29;
8else
9days = 28;
10break;
11case 4, 6, 9, 11:
12days = 30;
13break;
14}
15println("Anzahl der Tage im Monat " + days);
16}
1void main() {
2var month = Integer.parseInt(readln("Welchen Monate haben wir(1-12)? "));
3// seit Java 14:
4int days = switch (month) { // Switch-Ausdruck
5case 2:
6yield readln("Schaltjahr (j/n)? ").charAt(0) == 'j' ? 29 : 28;
7case 4, 6, 9, 11:
8yield 30;
9default:
10yield 31;
11};
12println("Anzahl der Tage im Monat " + days);
13}
case L ->
case <Literal> -> <Ausdruck oder Block>
.
Auf der rechten Seite ist nur ein Ausdruck oder ein Block erlaubt - keine Anweisung.
Bei dieser Variante gibt es kein durchfallen Fall-Through-Effekt, d. h. ein break
ist nicht zur Beendigung eines case
-Blocks zu verwenden!
1void main() {
2var month = Integer.parseInt(readln("Welchen Monate haben wir(1-12)? "));
3int days = 31;
4switch (month) { // seit Java 14
5case 2 -> { // Block oder Ausdruck!
6if (readln("Schaltjahr (j/n)? ").charAt(0) == 'j')
7days = 29;
8else
9days = 28;
10}
11case 4, 6, 9, 11 ->
12days = 30;
13}
14println("Anzahl der Tage im Monat " + days);
15}
1void main() {
2var month = Integer.parseInt(readln("Welchen Monate haben wir(1-12)? "));
3// seit Java 14:
4int days = switch (month) { // Switch-Ausdruck
5case 2 -> readln("Schaltjahr (j/n)? ").charAt(0) == 'j' ? 29 : 28;
6case 4, 6, 9, 11 -> 30;
7default -> 31;
8};
9println("Anzahl der Tage im Monat " + days);
10}
Als Wert im case
-Block können Literale vom Datentyp int
und ab Java 7 auch String
und Aufzählungen (enum
Klassen) verwendet werden; ab Java 21 wird der Musterabgleich (pattern matching) unterstützt es können auch beliebige (sogenannte) Referenztypen (nicht nur String
) verwendet werden. Wir werden dies später bei der Diskussion von Referenztypen detailliert behandeln.
case L ->
wird erst seit Java 14 unterstützt. Ein Mischen ist nicht möglich.
switch-Anweisung ≘ switch-statement
switch-Ausdruck ≘ switch-expression
switch
-Anweisung/-Ausdruck mit Musterabgleich und when
Bedingungen (seit Java 21)Seit Java 21 werden auch case
-Label unterstützt, die Muster abgleichen (match a pattern), und die mit when
-Bedingungen kombiniert werden können.
case <Pattern> when <Bedingung> -> <Ausdruck oder Block>
.
1void main() {
2var name = readln("Wie ist Dein Name? ");
3String nameAnalysis = switch (name) {
4// Der erste Vergleich, der zutrifft, wird ausgeführt.
5case "Michael", "Tom", "Erik" -> "m";
6case "Alice", "Eva", "Maria", "Eva-Maria" -> "w";
7case String s when s.length() < 2 -> "kein Name";
8case _ when name.contains("-") -> "Doppelname";
9default -> "<unbekannt>";
10};
11println("Namensanalyse = " + nameAnalysis);
12}
Erfolgreicher Musterabgleich?
Bei welchem Name wäre ein erfolgreicher Musterabgleich in mehreren Fällen möglich?
Wir werden Pattern Matching später detailliert behandeln.
Bei if
-/else
-Anweisungen werden die Prüf-Ausdrücke sequentiell (in der angegebenen Reihenfolge) ausgewertet (ein Ausdruck pro Alternative).
Bei switch
-Anweisungen/-Ausdrücken wird nur ein einziger Prüf-Ausdruck ausgewertet und die entsprechende(n) Alternative(n) direkt oder zumindest sehr effizient ausgeführt.
Daher benötigt die Auswertung einer switch
-Anweisung i. d. R. weniger Rechenschritte als eine äquivalente if
-/else
-Anweisung.
Wochentag benennen
Berechnen Sie den Wochentag für ein gegebenes Datum.
Lesen Sie (a) den Tag des Monats, (b) den Monat, (c) ob das Jahr ein Schaltjahr ist und (d) den Wochentag des 1. Januars des Jahres von der Konsole ein. Benutzen Sie die switch
und/oder if
-Anweisungen und geben Sie den Wochentag des gegebenen Datums auf der Konsole aus.
Beispielinteraktion:
# java --enable-preview Wochentag.java
Welchen Monat haben wir (1-12)? 12
Welchen Tag des Monats haben wir (1-28/29/30/31)? 24
Welcher Wochentag war der 1. Januar (0=Montag, 1=Dienstag, ..., 6=Sonntag)? 0
Ist das Jahr ein Schaltjahr (j/n)? j
> Tag im Jahr: 359
> Tag in der Woche: 2
> Der 24.12. ist ein Dienstag
Heimaufgabe: Erlauben Sie statt der Eingabe einer Zahl für den Wochentag auch die Eingabe des Wochentages als Text (z. B. "Montag", "Dienstag", ...).
Schleifen dienen dazu gleiche Anweisungen bzw. Blöcke mehrfach auszuführen
Schleifen zählen wie auch bedingte Anweisungen zu den Befehlen der Kontrollflußsteuerung
Schleifen können in Java-Programmen mittels for-Anweisungen, while-Anweisung und do-while-Anweisungen umgesetzt werden
Es muss darauf geachtet werden, dass keine Endlosschleifen entstehen
for
-Schleife1int sum = 0;
23
// for(<Init>; <Ausdruck>; <Update>) <Anweisung>
4for(int i = 0; i < 10 ; ++i ){
5sum += i;
6System.out.println("sum="+sum);
7}
Die for
-Schleife setzt sich zusammen aus einer Initialisierungsliste (<Init>), einer Abbruchbedingung <Ausdruck>, einer Änderungsliste (<Update>) und einen Schleifenrumpf (<Anweisung> bzw. <Block>). Alle drei Teile sind optional.
for(<Init>;<Ausdruck>;<Update>) <Anweisung> bzw. <Block>
wird vor dem ersten evtl. Schleifendurchlauf ausgeführt
wird vor jedem Schleifendurchlauf geprüft
wird nach einem Schleifendurchlauf ausgeführt
Sowohl die Initialisierungsliste als auch die Änderungsliste können mehrere Ausdrücke enthalten, die durch Kommas getrennt sind.
Beispiel:
1int sum=0;
23
4
for(int i = 0, j = 2; i < 10; ++i, j+=2 ){
5sum +=j;
6System.out.println("sum="+sum);
7}
1int sum=0;
2int i=0;
3int j=2;
4for(i++, j--; i < 10 ; ++i, j+=2 ){
5sum +=j;
6System.out.println("sum="+sum);
7}
Gültiger Code:
for(;;) { System.out.println("forever"); }
while
-Schleife1int sum = 0;
2int i = 0;
34
// while(<Ausdruck>) <Anweisung oder Block>
5while(i < 10){
6sum += i;
7System.out.println("sum=" + sum);
8++i;
9}
Die while
-Anweisung setzt sich zusammen aus einem <Ausdruck> als Abbruchbedingung und einen Schleifenrumpf (<Anweisung> bzw. <Block>).
Die Abbruchbedingung wird vor jedem Schleifendurchlauf geprüft.
while(<Ausdruck>) <Anweisung> bzw. <Block>
do
-while
-Schleifeint sum=0;
int i=0;
// do <Anweisung> while (<Ausdruck>);
do {
sum += i++;
System.out.println("sum="+sum);
} while(i < 10);
Die do
-while
-Schleife setzt sich zusammen aus einem Schleifenrumpf (<Anweisung> bzw. <Block>) und einem <Ausdruck> als Abbruchbedingung.
Die Abbruchbedingung wird nach jedem Schleifendurchlauf geprüft.
Im Gegensatz zur while
-Schleife wird der Schleifenrumpf mindestens einmal ausgeführt, bevor die Abbruchbedingung geprüft wird.
1int sum = 0;
23
for (int i = 0; i < 10; ++i) {
4if ((i + 1) % 5 == 0)
5break;
67
sum += i;
8System.out.println("i=" + i);
9}
10System.out.println("sum=" + sum);
1int sum = 0;
23
for (int i = 0; i < 10; ++i) {
4if ((i + 1) % 5 == 0)
5continue;
67
sum += i;
8System.out.println("i=" + i);
9}
10System.out.println("sum=" + sum);
1int sum = 0;
23
outer: for (int i = 0; i < 10; ++i) {
4System.out.println("i=" + i);
56
for (int j = 0; j < i; ++j) {
7System.out.println("j=" + j);
8if ((j + 1) % 5 == 0)
9break outer;
10sum += j;
11}
1213
sum += i;
14}
15System.out.println("sum=" + sum);
Mit den Anweisungen break
, break <Marke>
, continue
und continue <Marke>
kann die Abarbeitung einer Schleife beeinflusst werden.
Bei break
wird die Ausführung des aktuellen Schleifendurchlaufs abgebrochen und mit der Anweisung direkt nach dem Schleifenrumpf fortgefahren.
Bei continue
wird die Ausführung des aktuellen Schleifendurchlaufs abgebrochen und zum nächsten Schleifendurchlauf gesprungen.
break <Marke>
bricht auch die Ausführung des aktuellen Schleifendurchlaufs ab und es wird zur Anweisung nach einem Schleifenrumpf der Schleife mit der gegebenen Marke gesprungen.
Eine Marke setzt sich zusammen aus einem Java-Bezeichner und einem „:“ und kann vor einer Schleife bzw. einem Block stehen
Corner Cases
jshell> farOuter: for (int j = 0 ; j < 5 ; j++)
outer: for(int i = 0; i < 5; i++) {
System.out.println(j+" "+i); break farOuter;
}
0 0
jshell> farOuter: for (int j = 0 ; j < 5 ; j++)
outer: for(int i = 0; i < 5 ; i++) {
System.out.println(j+" "+i); continue farOuter;
}
0 0
1 0
2 0
3 0
4 0
Einfacher Primzahltest
Verwenden Sie eine Schleife, um festzustellen ob eine Zahl eine Primzahl ist. Lesen Sie die Zahl von der Konsole ein. Geben Sie am Ende aus, ob die Zahl eine Primzahl ist oder nicht; geben Sie ggf. auch den kleinsten Teiler der Zahl aus.
Schreiben Sie den Code für den Java Interpreter.
Es ist nicht erforderlich, dass der Algorithmus effizient ist.
Beispielinteraktion:
# java --enable-preview Primzahltest.java
Geben Sie eine ganze positive Zahl ein? 97
97 ist eine Primzahl
# java --enable-preview Primzahltest.java
Geben Sie eine ganze positive Zahl ein? 123
3 ist ein Teiler von 123
Berechnung der Kubikwurzel mit Newton-Raphson
Berechnen Sie die Kubikwurzel \(x\) einer Zahl \(n\) mit Hilfe einer Schleife. Nutzen Sie dazu das schnell konvergierende, iterative Verfahren von Newton-Raphson.
Beispielinteraktion:
# java --enable-preview KubikwurzelMitSchleife.java 10:43:30
Geben Sie eine Zahl n ein deren Kubikwurzel w Sie berechnen wollen
(d.h. n = w*w*w): 1000000
Wie viele Schritte wollen Sie machen? 50
...
Das Ergebnis ist: 100.0
Stellen Sie sich die folgenden Fragen:
Welchen Datentyp sollten Sie für die Kubikwurzeln verwenden?
Macht es Sinn die Anzahl der Iterationen zu begrenzen?
(D. h. wie schnell konvergiert das Verfahren?)
Können Sie die Kubikwurzel von 2.251.748.274.470.911 (2251748274470911
) berechnen?
Wie kann man feststellen ob eine gute Näherung an die Kubikwurzel vorliegt?
Um zu verstehen wie schnell der Algorithmus konvergiert können sie sich den aktuellen Wert \(x_n\) ausgeben lassen.
Hausübung: Implementieren Sie den Algorithmus auch mit einem anderen Typ von Schleife.
Methoden in Java-Programmen dienen dazu die Anwendungslogik zu strukturieren und in wiederverwendbare Unterprogramme zu zerlegen.
Methoden können von einer anderen Methode aufgerufen werden.
Eine Methode hat einen Namen, eine Parameterliste und einen Rückgabetyp.
Methoden können bzw. müssen weiterhin deklarieren welche Ausnahmen auftreten können. Dies werden wir aber erst später behandeln.
Der Methodenrumpf ist eine Abfolge von Anweisungen bzw. Blöcken.
<Rückgabetyp> <Methodenname> (<Parameterliste>){
<Methoden-Rumpf>
}
Wir haben bereits Methoden wie println(String)
und double Double.parseDouble(String)
kennengelernt.
Wenn wir void main() { ... }
verwenden, dann definieren wir eine Methode, die von der Java-Laufzeitumgebung beim Start aufgerufen wird.
Per Konvention ist festgelegt, dass diese Methode
main
heisst.
Beispiel
Deklaration einer Methode zum Berechnen des größten gemeinsamen Teilers (ggt
) zweier Zahlen.
1int ggt(int z1, int z2) { // Algorithmus von Euklid
2z1 = Math.abs(z1);
3z2 = Math.abs(z2);
45
int rest = 0;
6while (z2 != 0) {
7rest = z1 % z2;
8z1 = z2;
9z2 = rest;
10}
11return z1; // return bestimmt welcher Wert zurückgegeben wird
12}
Im ggtEuklid
-Beispiel werden die Parameter als normale Variablen behandelt. Dies wurde hier aus Kompaktheitsgründen so gewählt. Im Allgemeinen sollten die Parameter als Konstanten betrachtet werden, d. h. sie sollten nicht verändert werden.
Die Parameterliste definiert über eine komma-separierte Liste die optionalen formalen Parameter der Methode:
<Typ> <Bezeichner> (, <Typ> <Bezeichner>)*
Rückgabewerte werden im Methodenrumpf mit der return Anweisung zurückgegeben:
return <Ausdruck>
Bei Methoden ohne Rückgabewert (void
) dient die leere return
Anweisung (return ;
) zum - ggf. vorzeitigem - Beenden der Methode. Am Ende der Methode ist in diesem Fall die return
Anweisung optional.
Der Aufruf erfolgt durch die Angabe des Klassennamens, des Methodennamens und der aktuellen Parameterwerte.
<Methode>(<Parameterwerte>)
Als aktuelle Parameterwerte können Variablen, Ausdrücke oder Literale übergeben werden.
Der Datentyp des übergebenen Wertes muss in den Datentyp des formalen Parameters implizit konvertierbar sein. Andernfalls muss explizit konvertiert werden.
Von allen übergebenen Werten wird eine (ggf. flache) Kopie übergeben.
D. h. Änderungen an den Parametern innerhalb der Methode haben keine Auswirkungen auf die Werte der Argumente (Fachbegriff: call-by-value).
Methoden dürfen sich selber aufrufen (Rekursion).
Schleifen basierte Implementierung des Algorithmus von Euklid:
1int ggt(int z1, int z2) {
2int rest = 0;
3while (z2 != 0) {
4rest = z1 % z2;
5z1 = z2;
6z2 = rest;
7}
8return z1;
9}
Elegante rekursive Implementierung des Algorithmus von Euklid:
int ggt(int z1, int z2) {
if (z2 == 0)
return z1;
else
return ggt(z2, z1 % z2);
}
Eine überladene Methode ist eine Methode mit dem gleichen Namen wie eine andere Methode, aber mit einer unterschiedlichen Parameterliste. Folgende Unterschiede sind möglich:
Eine Methode definiert eine unterschiedliche Anzahl von Parametern
Eine Methode hat unterschiedliche Datentypen für ihre formalen Parameter
Unterschiedliche Rückgabetypen sind in Java nicht ausreichend.
Zum Beispiel gibt es in Java die Methode int Math.max(int, int)
und double Math.max(double, double)
.
max(long, long)?
Warum definiert Java auch noch die Methode long Math.max(long, long)
bzw. warum reicht es nicht aus nur long Math.max(long, long)
zu definieren und auf int Math.max(int, int)
zu verzichten?
void print(int i) {
println("int: " + i);
}
void print(double d) {
println("double: " + d);
}
void main() {
int i = 1;
print(i);
float f = 1.0f;
print(f);
}
Für den Moment ist eine Klasse für uns eine Sammlung von Methoden und Konstanten, die inhaltlich in einem logischen Zusammenhang stehen.
Der Aufruf einer Methode einer Klasse erfolgt durch die Angabe des Klassennamens, des Methodennamens und der aktuellen Parameterwerte.
<Klasse>.<Methode>(<Parameterwerte>)
Wir haben bereits entsprechende Beispiele gesehen, z. B. Double.parseDouble(String)
oder Integer.parseInt(String)
.
Hinweis
Auf diese Weise können nur statische Methoden aufgerufen werden. Die Details werden wir später beim Thema Klassen und Objekte behandeln.
Methoden definieren
Nehmen Sie die Ergebnisse der letzten Übung und definieren Sie jeweils eine Methode für die Berechnung der Kubikwurzel
und für den Primzahltest. Die Methode isPrime
soll dabei den Rückgabetyp boolean haben.
Auf die Ausgabe des kleinsten Teilers beim Primzahltest soll verzichtet werden.
Rufen Sie die Methoden aus Ihrer main
-Methode auf. Die main
-Methode soll dabei nur die Eingabe und die Ausgabe übernehmen.
Wandeln Sie die Methode für die Berechnung der Kubikwurzel in eine rekursive Methode um.
MTAwMDAw:+gZW6Vdoz0cTiI0yNfDtuF/v4EhuaGafeiV8WqjluIE=:Axoes72UoVtiWLeH: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
Fakultät berechnen
Schreiben Sie eine nicht-rekursive Methode zur Berechnung der Fakultät einer Zahl. Lesen Sie die Zahl von der Konsole ein und geben Sie die Fakultät auf der Konsole aus.
Halten Sie sich an die Java-Konventionen.
(Die Konventionen haben sich - aus guten Gründen - seit Jahrzehnten nicht geändert.)
Formatieren Sie Ihren Code konsistent; d. h. stellen Sie konsistente Einrückungen sicher!
Verwenden Sie inhaltsorientierte, sprechende Namen für Variablen, Konstanten, Methoden etc.
Hinweis
Manuelles formatieren ist nicht sinnvoll.
Verwenden Sie einen automatische Code-Formatter!
Rücken Sie zusammenhängende Blöcke um die gleiche Anzahl von Leerzeichen ein.
Gängig ist ein Vielfaches von 2 oder 4 Leerzeichen.
Verwenden Sie keine Tabulatoren (\\t) für Einrückungen.
Beginnt ein neuer Block innerhalb eines äußeren Blockes, so werden die zugehörigen Anweisungen tiefer eingerückt als der äußere Block.
Pro Zeile sollte nur ein Block oder eine Anweisung stehen.
Falsche Einrückung
int ggtNaiv(int z1, int z2){
int min = (z1>z2)?z2:z1; println("current min="+min);
for(int ggt=min; ggt>1; --ggt){
if(z1%ggt==0 && z2%ggt==0)
return ggt;
}
return 1;
}
}
Korrekte Einrückung
int ggtNaiv(int z1, int z2) {
int min = (z1 > z2) ? z2 : z1;
println("current min=" + min);
for (int ggt = min; ggt > 1; --ggt) {
if (z1 % ggt == 0 && z2 % ggt == 0)
return ggt;
}
return 1;
}
Verwenden Sie Klammern um Blöcke, auch wenn sie nur eine Anweisung enthalten.
(Insbesondere bei verschachtelten Blöcken bzw. If
-Anweisungen ist dies wichtig.)
Bei bedingten Anweisungen und Schleifen steht die öffnende geschweifte Klammer am Ende der 1. Zeile. Die schließende geschweifte Klammer steht in einer eigenen Zeile am Ende. Sie hat die gleiche Einrückung wie die Anweisung.
Warnung
Zeilen, die länger als 80 oder max. 100 Zeichen erfordern beim Lesen horizontales Scrollen und sind unter allen Umständen zu vermeiden!
Konfigurieren Sie Ihren Editor so, dass Sie unmittelbar sehen, wenn eine Zeile zu lang wird.
Dokumentieren Sie Ihre Methoden und Klassen mit Javadoc-Kommentaren.
Dokumentieren Sie insbesondere die Vor- und Nachbedingungen von Methoden.
Dokumentieren Sie die Anforderungen an die Parameter.
Zum Beispiel: @param n die Zahl für die die Fakultät berechnet wird; n>=0 und n < 13
Dokumentieren Sie die Rückgabewerte.
Zum Beispiel: @return die Fakultät von n
Der erste Satz eines Javadoc-Kommentar sollte eine kurze, vollständige Beschreibung der Methode enthalten. Dieser wird in der Übersicht verwendet.
Zum Beispiel: Berechnet die Fakultät einer Zahl n
Dokumentieren Sie keine Trivialitäten
Zum Beispiel: i++; // erhöhe i um 1
Wenn Sie einen Bedarf sehen, innerhalb einer Methode Kommentare zu schreiben, dann ist dies häufig ein Hinweis darauf, dass der Code refaktorisiert (refactored) werden sollte.
Zum Beispiel könnten die Methode in kleinere Methoden aufgeteilt werden.
Dokumentieren Sie insbesondere das, was nicht im Code steht und was nicht offensichtlich ist.
KI Tools (zum Beispiel GitHub Copilot) sind bereits jetzt in der Lage gute initiale Kommentare zu generieren. Aber häufig fehlt die Dokumentation der (impliziten/globalen) Anforderungen sowie der Vor- und Nachbedingungen.
Woher könnte die Anforderung n < 13
für die Fakultät kommen?
die Java-Konventionen sind allgemein gültig und sollten eingehalten werden, decken aber nicht alle Teile des Codes ab.
In einem Team oder Projekt können spezifische Konventionen festgelegt werden, die über die allgemeinen Konventionen hinausgehen. Diese sollten dann automatisiert überprüft und ggf. automatisch formatiert werden.
Beispiele sind:
Einrückungen der Parameter bei Methoden mit vielen Parametern.
Sprache in der Variablen benannt werden. (z. B. Fachsprache in Englisch oder Deutsch)
Maximale Einrückungstiefe von Schleifen und Bedingungen.
...
Überprüfen Sie den von Ihnen geschrieben Code auf korrekte Formatierung.
Installieren Sie für VS Code das Java Extension Pack und verwenden Sie den eingebauten Code Formatter über die entsprechende Tastenkombination.
(Auf Mac mit Standardeinstellungen zum Beispiel: Shift + Alt + F.)
Schreiben Sie für die Methoden passende Kommentare im Javadoc-Stil.
Am Ende diskutieren wir Ihren Code/Ihre Kommentare.
Auf dem Weg zu einem professionellen Programmierer (egal welcher Sprache) ist es wichtig, neben den Sprachkonstrukten auch die geltenden Konventionen zu erlernen und einzuhalten. Diese sind je nach Sprache meist leicht unterschiedlich, aber in der Regel sehr ähnlich.
Das Einhalten fördert die Zusammenarbeit mit anderen Programmieren - insbesondere auch Ihrem zukünftigen Ich - und erhöht die Lesbarkeit des Codes.
Assertions sind eine Möglichkeit, um sicherzustellen, dass bestimmte Bedingungen erfüllt sind.
assert <Bedingung>;
bzw.
assert <Bedingung>: <Ausdruck>;
Die Bedingung muss ein boolescher Ausdruck sein. Der Ausdruck ist optional und wird nur ausgewertet, wenn die Bedingung falsch ist. Normalerweise wird der Ausdruck verwendet, um eine Fehlermeldung zu erzeugen.
Beispiel: Funktion mit Assertion
/// Berechnet den GGT
///
/// @param z1 die erste Zahl; `z1 >= 0`
/// @param z2 die zweite Zahl; `z2 >= 0`
/// @return den GGT von z1 und z2
int ggt(int z1, int z2) {
assert z1 >= 0 && z2 >= 0 : "z1 und z2 müssen >= 0 sein";
if (z2 == 0)
return z1;
else
return ggt(z2, z1 % z2);
}
ggt(-2,4) // ==> Exception java.lang.AssertionError: z1 und z2 müssen >= 0 sein
Assertions sind gut geeignet zur Überprüfung von:
(Internen) Invarianten
Kontrollfluss-Varianten
Vorbedingungen, Nachbedingungen
Warnung
Die Auswertung der Bedingung sollte keine Seiteneffekte haben, da diese nur bei aktivierten Assertions überhaupt ausgeführt wird und dies auch die Erwartungen anderer Programmierer verletzen würde.
Beispiel: Assertion mit Seiteneffekt
int ggt(int z1, int z2) {
// ⚠️ Seiteneffekt, der den Fehler (sogar) korrigiert...
assert (z1 = Math.abs(z1)) >= 0 && (z2 = Math.abs(z2)) >= 0;
if (z2 == 0) return z1;
else return ggt(z2, z1 % z2);
}
Hinweis
Java Assertions sollten nur für Bedingungen verwendet werden, die niemals falsch sein dürfen.
Assertions dienen der Identifikation von Programmierfehlern und sollten nicht für Bedingungen verwendet werden, die auf zu erwartende Fehler zurückzuführen sind. (Z. B. falsche Nutzereingaben oder Netzwerkfehler etc.)
Assertions werden in Java nur bei expliziter Aktivierung überprüft.
Um im Code zu prüfen, ob Assertions aktiviert sind, kann folgender (auf einem Seiteneffekt basierender) Code verwendet werden:
var assertionsEnabled = false;
assert (assertionsEnabled = true);
if (assertionsEnabled) { ... }
Um Assertions zu aktivieren, müssen Sie den Kommandozeilenparameter -ea
oder -enableassertions
verwenden. Bzw. bei der JShell -R -ea
.
Zum Beispiel können Sie die JShell wie folgt starten:
jshell --enable-preview -R -ea
Die Tatsache, dass Assertions nur bei expliziter Aktivierung überprüft werden, ist einer der größten Kritikpunkte an Java Assertions.
Assertions
Erweitern Sie Ihre Methode zur Berechnung der Fakultät um Assertions, die sicherstellen, dass die Eingabe nicht negativ und nicht größer als 20 ist.