diff --git a/docs/additional-material/instructions/binary-numbers.mdx b/docs/additional-material/instructions/binary-numbers.mdx index 78626717bb..f278071789 100644 --- a/docs/additional-material/instructions/binary-numbers.mdx +++ b/docs/additional-material/instructions/binary-numbers.mdx @@ -10,8 +10,8 @@ import TabItem from '@theme/TabItem'; ## Binärzahlen in Dezimalzahlen umwandeln -Zur Umwandlung einer Binärzahl in eine Dezimalzahl muss das Produkt aus -Stellenwert und Ziffer jeder Stelle aufsummiert werden. +Um eine Binärzahl in eine Dezimalzahl umzuwandeln, wird das Produkt aus +Stellenwert und Ziffer jeder Stelle aufsummiert. | Potenz | Stellenwert | Ziffer | Stellenwert \* Ziffer | | -------------- | ----------- | ------ | --------------------- | @@ -30,8 +30,8 @@ Stellenwert und Ziffer jeder Stelle aufsummiert werden. ## Natürliche Dezimalzahlen in Binärzahlen umwandeln -Zur Umwandlung einer natürlichen Dezimalzahl in eine Binärzahl kann entweder -eine Stellenwerttabelle oder das Divisions-Verfahren verwendet werden. +Eine natürliche Dezimalzahl lässt sich entweder mit einer Stellenwerttabelle +oder dem Divisions-Verfahren in eine Binärzahl umwandeln. Im Beispiel soll die Zahl 52510 in eine Binärzahl umgewandelt werden. @@ -76,10 +76,9 @@ Im Beispiel soll die Zahl 52510 in eine Binärzahl umgewandelt werden ## Bilden des Zweierkomplements -Zum Bilden des Zweierkomplements wird zunächst das Einerkomplement gebildet, -d.h. alle Bits werden invertiert. Hierbei ist zu beachten, dass einer positiven -Binärzahl unendlich viele Nullen vorangestellt sind. Anschließend wird noch eine -1 hinzuaddiert. +Das Zweierkomplement entsteht, indem zunächst das Einerkomplement gebildet wird +(alle Bits werden invertiert) und anschließend eine 1 hinzuaddiert wird. Einer +positiven Binärzahl sind dabei unendlich viele Nullen vorangestellt. Im Beispiel soll die Zahl -9510 im Zweierkomplement dargestellt werden. @@ -90,7 +89,7 @@ werden. | Invertieren | 1 | ... | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | | 1 Addieren | 1 | ... | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | -:::info +:::note Die Rückumwandlung erfolgt analog. @@ -98,8 +97,8 @@ Die Rückumwandlung erfolgt analog. ## Reelle Dezimalzahlen in Binärzahlen umwandeln -Zur Umwandlung einer reellen Dezimalzahl in eine Binärzahl kann entweder eine -Stellenwerttabelle oder das Multiplikations-Verfahren verwendet werden. +Eine reelle Dezimalzahl lässt sich entweder mit einer Stellenwerttabelle oder +dem Multiplikations-Verfahren in eine Binärzahl umwandeln. Im Beispiel soll die Zahl 0,110 in eine Binärzahl umgewandelt werden. @@ -138,12 +137,12 @@ Im Beispiel soll die Zahl 0,110 in eine Binärzahl umgewandelt werden ## Reelle Dezimalzahlen in Gleitkommazahlen umwandeln -Bei der Umwandlung einer reellen Zahl in eine Gleitkommazahl werden zunächst -Vor- und Nachkommazahl in Binärzahlen umgewandelt. Anschließend wird durch -Gleiten bzw. Verschieben des Kommas zur führenden 1, dem Runden auf das LSB -sowie dem Entfernen der führenden 1 die Mantisse ermittelt. Nach dem Ermitteln -der Mantisse wird zum Exponenten noch der Bias (127 bei einfacher Genauigkeit, -1023 bei doppelter Genauigkeit) hinzuaddiert sowie das Vorzeichen umgewandelt. +Bei der Umwandlung einer reellen Zahl in eine Gleitkommazahl werden Vor- und +Nachkommazahl zunächst in Binärzahlen umgewandelt. Durch Verschieben des Kommas +zur führenden 1, Runden auf das LSB und Entfernen der führenden 1 entsteht die +Mantisse. Zum Exponenten wird anschließend der Bias addiert (127 bei einfacher, +1023 bei doppelter Genauigkeit), und das Vorzeichen wird als einzelnes Bit +gespeichert. Im Beispiel soll die Zahl -27,0410 in eine Gleitkommazahl mit einfacher Genauigkeit umgewandelt werden. @@ -163,16 +162,14 @@ einfacher Genauigkeit umgewandelt werden. ## Binärzahlen addieren und subtrahieren -Für die Addition von Binärzahlen gelten folgende Regeln: +Für die Addition von Binärzahlen gelten vier Regeln. Die Subtraktion erfolgt +durch Addition des Zweierkomplements: `a - b = a + (-b)`. - Fall 1: `0 + 0 = 0` - Fall 2: `0 + 1 = 1` - Fall 3: `1 + 0 = 1` - Fall 4: `1 + 1 = 0 (Übertrag 1)` -Die Subtraktion von Binärzahlen erfolgt durch die Addition des -Zweierkomplements. Es gilt: `a - b = a + (-b)`. - @@ -228,9 +225,9 @@ Im Beispiel werden die Zahlen -3 und -47 addiert. -:::info +:::note -Der bei der Addition des Zweierkomplements auftretende mögliche Stellenüberlauf -wird ignoriert. +Der bei der Addition des Zweierkomplements möglicherweise auftretende +Stellenüberlauf wird ignoriert. ::: diff --git a/docs/additional-material/instructions/debugging.md b/docs/additional-material/instructions/debugging.md new file mode 100644 index 0000000000..ca0e5ad4bc --- /dev/null +++ b/docs/additional-material/instructions/debugging.md @@ -0,0 +1,128 @@ +--- +title: Debuggen mit Eclipse +description: '' +sidebar_position: 50 +tags: [debugging, eclipse] +--- + +:::tip + +Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/) und +[Eclipse](https://www.eclipse.org/) + +::: + +Der in Eclipse integrierte Debugger ermöglicht es, ein Java-Programm +kontrolliert auszuführen, an beliebigen Stellen anzuhalten und den Zustand von +Variablen sowie den Programmfluss zu inspizieren. Die folgenden Abschnitte +führen schrittweise durch die wichtigsten Debugging-Funktionen in Eclipse. + +## Programm im Debug-Modus starten + +Um den Debugger zu nutzen, muss das Programm explizit im Debug-Modus gestartet +werden. Ohne diesen Modus sind Breakpoints und Schrittausführung nicht +verfügbar. + +- Öffne das gewünschte Java-Projekt in Eclipse +- Navigiere im _Package Explorer_ zur Startklasse (der Klasse mit der + `main`-Methode) +- Öffne das Kontextmenü der Startklasse (Rechtsklick) und führe **Debug As → + Java Application** aus + +:::tip + +Das Programm kann alternativ über die Werkzeugleiste mit der Schaltfläche +**Debug** (Käfer-Symbol) oder mit dem Tastaturkürzel `F11` im Debug-Modus +gestartet werden. + +::: + +## Breakpoint setzen + +Ein Breakpoint markiert eine Zeile, an der die Programmausführung pausieren +soll. Eclipse hält an dieser Stelle an, bevor die markierte Zeile ausgeführt +wird. + +- Navigiere im Editor zur gewünschten Zeile +- Führe im grauen Randbereich links der Zeilennummer (Rechtsklick) die Funktion + **Toggle Breakpoint** aus + +Ein blauer Kreis im Randbereich zeigt an, dass der Breakpoint aktiv ist. + +:::tip + +Ein Breakpoint kann auch durch einen Doppelklick auf den grauen Randbereich +links der Zeilennummer gesetzt bzw. entfernt werden. + +::: + +## Debug-Perspektive verwenden + +Sobald das Programm an einem Breakpoint anhält, wechselt Eclipse automatisch in +die _Debug-Perspektive_. Sie besteht aus mehreren spezialisierten Ansichten, die +gemeinsam ein vollständiges Bild des aktuellen Programmzustands liefern. + +- **Debug**: zeigt den Call Stack (Aufrufhierarchie der aktiven Methoden) +- **Variables**: zeigt alle aktuell sichtbaren Variablen und deren Werte +- **Breakpoints**: listet alle gesetzten Breakpoints und erlaubt das + Aktivieren/Deaktivieren einzelner Breakpoints +- **Console**: zeigt die Standardausgabe des laufenden Programms +- **Expressions**: wertet beliebige Java-Ausdrücke im aktuellen Kontext aus + (z.B. `list.size()` oder `obj.getName()`) + +## Programm schrittweise ausführen + +Sobald das Programm an einem Breakpoint pausiert, stehen verschiedene +Schritt-Befehle zur Verfügung, um die Ausführung gezielt fortzusetzen und den +Kontrollfluss zu verfolgen. + +- Führe **Run → Step Over** (`F6`) aus, um die aktuelle Zeile vollständig + auszuführen und in der nächsten Zeile derselben Methode anzuhalten +- Führe **Run → Step Into** (`F5`) aus, um in den Rumpf des aufgerufenen + Methodenaufrufs hineinzuspringen +- Führe **Run → Step Return** (`F7`) aus, um die aktuelle Methode vollständig + auszuführen und zur aufrufenden Stelle zurückzukehren +- Führe **Run → Resume** (`F8`) aus, um die Ausführung bis zum nächsten + Breakpoint fortzusetzen + +## Variablenwerte inspizieren + +Die View _Variables_ zeigt den aktuellen Zustand aller sichtbaren Variablen. +Objekte können aufgeklappt werden, um ihre Felder zu inspizieren. + +- Navigiere in der Debug-Perspektive zur View _Variables_ +- Klappe Objekte durch Betätigen des Dreiecks links des Variablennamens auf +- Der aktuelle Wert einer Variablen wird in der Spalte **Value** angezeigt + +:::tip + +Fahre im Editor mit der Maus über einen Variablennamen, um dessen aktuellen Wert +als Tooltip anzuzeigen. Für komplexere Ausdrücke steht die View _Expressions_ +zur Verfügung: Rechtsklick im Editor → **Watch**. + +::: + +## Bedingten Breakpoint setzen + +Ein bedingter Breakpoint pausiert die Ausführung nur dann, wenn eine angegebene +boolesche Bedingung erfüllt ist. Das ist besonders nützlich, wenn ein Fehler nur +bei bestimmten Werten auftritt – etwa ab einem bestimmten Schleifendurchlauf. + +- Setze zunächst einen gewöhnlichen Breakpoint (siehe oben) +- Führe im Randbereich auf dem Breakpoint-Symbol (Rechtsklick) die Funktion + **Breakpoint Properties...** aus +- Aktiviere die Option **Enable Condition** +- Trage eine boolesche Bedingung im Textfeld ein (z.B. `i == 42`) +- Betätige **OK** + +Der Breakpoint pausiert die Ausführung nun nur noch, wenn die angegebene +Bedingung `true` ergibt. + +## Debug-Perspektive verlassen + +Nach dem Abschluss der Fehlersuche sollte die Debug-Perspektive ordentlich +beendet und zur Java-Perspektive zurückgewechselt werden. + +- Führe **Run → Terminate** (`Ctrl+F2`) aus, um das laufende Programm zu beenden +- Wechsle über den Perspektiven-Umschalter in der Werkzeugleiste (oben rechts) + zurück zur _Java_-Perspektive diff --git a/docs/additional-material/instructions/git.md b/docs/additional-material/instructions/git.md index 919ccb3dc6..2719004dc7 100644 --- a/docs/additional-material/instructions/git.md +++ b/docs/additional-material/instructions/git.md @@ -5,7 +5,7 @@ sidebar_position: 30 tags: [git] --- -:::info +:::tip Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/), [Eclipse](https://www.eclipse.org/) und [Git](https://git-scm.com/downloads) @@ -14,6 +14,10 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/), ## Remote Repository anlegen +Ein Remote Repository auf GitHub dient als zentraler Ablageort für den +Quellcode. Zusätzlich wird ein Personal Access Token benötigt, um sich von der +Kommandozeile aus zu authentifizieren. + - Registriere Dich bei [GitHub](https://github.com/) - Melde Dich bei [GitHub](https://github.com/) an - Führe die Funktion **New** aus @@ -32,6 +36,9 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/), ## Git konfigurieren +Vor der ersten Nutzung muss Git mit dem eigenen Namen und der E-Mail-Adresse +konfiguriert werden. Diese Angaben erscheinen in jedem Commit. + - Starte die Kommandozeile (z.B. Windows PowerShell) - Führe den Befehl `git config --global user.name "[Dein Name]"` aus, um den Benutzernamen festzulegen (z.B. @@ -42,6 +49,9 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/), ## Lokales Repository anlegen +Ein lokales Repository kann entweder neu initialisiert (Variante A) oder direkt +vom Remote Repository geklont werden (Variante B). + **Variante A: Via Git Init** - Starte die Kommandozeile (z.B. Windows PowerShell) @@ -70,6 +80,8 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/), ## Lokales Repository in Eclipse einbinden +Nach dem Anlegen des lokalen Repositorys wird es als Eclipse-Projekt importiert. + - Starte Eclipse - Führe die Funktion **File - Import... - General - Projects from Folder or Archive** aus und betätige die Drucktaste **Next >** @@ -79,6 +91,10 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/), ## Remote Repository aktualisieren (bei Änderungen im lokalen Repository) +Lokale Änderungen werden indiziert, als Commit versioniert und anschließend ins +Remote Repository übertragen. Das ist entweder über die Kommandozeile oder +direkt in Eclipse möglich. + **Variante A: Via Kommandozeile** - Führe mehrmals den Befehl `git add [Die zu indizierende Datei]` aus, um die @@ -104,6 +120,10 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/), ## Lokales Repository aktualisieren (bei Änderungen im remote Repository) +Änderungen aus dem Remote Repository werden in den lokalen Arbeitsbereich +übertragen. Das ist entweder über die Kommandozeile oder direkt in Eclipse +möglich. + **Variante A: Via Kommandozeile** - Starte die Kommandozeile (z.B. Windows PowerShell) diff --git a/docs/additional-material/instructions/javafx.md b/docs/additional-material/instructions/javafx.md index f753f8747d..42e1c20f3c 100644 --- a/docs/additional-material/instructions/javafx.md +++ b/docs/additional-material/instructions/javafx.md @@ -5,7 +5,7 @@ sidebar_position: 40 tags: [javafx] --- -:::info +:::tip Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/), [Eclipse](https://www.eclipse.org/), @@ -16,6 +16,9 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/), ## Scene Builder mit Eclipse verbinden +Damit Eclipse den Scene Builder öffnen kann, muss der Pfad zur ausführbaren +Datei einmalig konfiguriert werden. + - Starte Eclipse - Navigiere zu **Window – Preferences – JavaFX** - Gib beim Feld **SceneBuilder executable** den Wert **[Der Pfad zur @@ -24,6 +27,10 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/), ## JavaFX-Anwendung ausführen +Eine JavaFX-Anwendung kann entweder als ausführbare JavaFX-Anwendung über das +Maven-Plugin (Variante A) oder über eine separate Startklasse (Variante B) +gestartet werden. + **Variante A: Via ausführbarer JavaFX-Anwendung** - Starte Eclipse @@ -97,6 +104,10 @@ public class MainClass { ## Ausführbare JavaFX-Anwendung debuggen +Um eine ausführbare JavaFX-Anwendung im Debug-Modus zu starten, wird das +JavaFX-Maven-Plugin um eine Debug-Konfiguration erweitert und anschließend mit +dem Goal `javafx:run@debug` ausgeführt. + - Starte Eclipse - Navigiere in der View _Package Explorer_ zu Deinem Maven-Projekt - Navigiere in Deinem Maven-Projekt zur Datei _pom.xml_ und öffne diese diff --git a/docs/additional-material/instructions/jdk.md b/docs/additional-material/instructions/jdk.md index 5897a65279..a475b5c856 100644 --- a/docs/additional-material/instructions/jdk.md +++ b/docs/additional-material/instructions/jdk.md @@ -5,7 +5,7 @@ sidebar_position: 10 tags: [jdk] --- -:::info +:::tip Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/) @@ -13,6 +13,10 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/) ## Quellcode-Datei erstellen +Eine Java-Quellcode-Datei enthält genau eine öffentliche Klasse, deren Name dem +Dateinamen entsprechen muss. Die Datei liegt in einem Paketordner und trägt die +Endung _.java_. + - Erstelle ein Arbeitsverzeichnis (z.B. _C:\Users\Daniel Appenmaier\Java_) - Erstelle im eben erstellten Arbeitsverzeichnis einen Ordner (z.B. _main_) - Erstelle im eben erstellten Ordner eine Datei mit der Endung _.java_ (z.B. @@ -34,6 +38,9 @@ public class HelloWorld { ## Quellcode-Datei kompilieren +Der Java-Compiler `javac` übersetzt die Quellcode-Datei in eine Bytecode-Datei +(_.class_). + - Starte die Kommandozeile (z.B. Windows PowerShell) - Führe den Befehl `cd "[Der Pfad zu Deinem Arbeitsverzeichnis]"` aus, um zum Arbeitsbereich zu wechseln (z.B. `cd "C:\Users\Daniel Appenmaier\Java"`) @@ -42,6 +49,8 @@ public class HelloWorld { ## Bytecode-Datei ausführen +Die Java Virtual Machine `java` führt die kompilierte Bytecode-Datei aus. + - Starte die Kommandozeile (z.B. Windows PowerShell) - Führe den Befehl `cd "[Der Pfad zu Deinem Arbeitsverzeichnis]"` aus, um zum Arbeitsbereich zu wechseln (z.B. `cd "C:\Users\Daniel Appenmaier\Java"`) diff --git a/docs/additional-material/instructions/maven.md b/docs/additional-material/instructions/maven.md index ba7c8d73ae..55fe172a2d 100644 --- a/docs/additional-material/instructions/maven.md +++ b/docs/additional-material/instructions/maven.md @@ -5,7 +5,7 @@ sidebar_position: 20 tags: [maven] --- -:::info +:::tip Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/) und [Eclipse](https://www.eclipse.org/) @@ -14,6 +14,9 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/) und ## Maven-Projekt anlegen +Ein neues Maven-Projekt wird direkt in Eclipse angelegt. Der Projektordner +sollte im Git-Arbeitsbereich liegen, damit er versioniert werden kann. + - Starte Eclipse - Führe die Funktion **File - New - Maven Project** aus - Markiere die Option **Create a simple project (skip archetype selection)**, @@ -33,6 +36,9 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/) und ## Java-Version und Codierung festlegen +Die Java-Version und die Zeichenkodierung werden in der _pom.xml_ über +Properties konfiguriert. + - Starte Eclipse - Navigiere in der View _Package Explorer_ zu Deinem Maven-Projekt - Navigiere in Deinem Maven-Projekt zur Datei _pom.xml_ und öffne diese @@ -53,6 +59,9 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/) und ## JavaDoc erstellen +Das JavaDoc-Maven-Plugin generiert eine HTML-Dokumentation aus den +Javadoc-Kommentaren im Quellcode. + - Starte Eclipse - Navigiere in der View _Package Explorer_ zu Deinem Maven-Projekt - Navigiere in Deinem Maven-Projekt zur Datei _pom.xml_ und öffne diese @@ -87,6 +96,9 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/) und ## Ausführbare JAR-Datei erstellen +Das Shade-Plugin verpackt das Projekt samt aller Abhängigkeiten in eine +ausführbare Über-JAR. + - Starte Eclipse - Navigiere in der View _Package Explorer_ zu Deinem Maven-Projekt - Navigiere in Deinem Maven-Projekt zur Datei _pom.xml_ und öffne diese @@ -104,7 +116,7 @@ Benötigte Tools: [JDK](https://www.oracle.com/java/technologies/downloads/) und org.apache.maven.plugins maven-shade-plugin - [Version]] + [Version] package diff --git a/docs/additional-material/tools/debugging.mdx b/docs/additional-material/tools/debugging.mdx new file mode 100644 index 0000000000..3d5c9d8e79 --- /dev/null +++ b/docs/additional-material/tools/debugging.mdx @@ -0,0 +1,146 @@ +--- +title: Debugging +description: '' +sidebar_position: 50 +tags: [debugging] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Debugging bezeichnet den Prozess des Auffindens und Behebens von Fehlern +(_Bugs_) in einem Programm. Fehler lassen sich in drei Kategorien einteilen: +_Syntaxfehler_ werden bereits beim Kompilieren erkannt, _Laufzeitfehler_ treten +erst während der Programmausführung auf (z.B. eine `NullPointerException`), und +_logische Fehler_ führen zu einem falschen Ergebnis, ohne dass das Programm +abstürzt. Während Syntaxfehler direkt von der IDE gemeldet werden, erfordern +Laufzeit- und logische Fehler den Einsatz eines _Debuggers_. + +Ein Debugger ermöglicht es, ein Programm kontrolliert auszuführen, an beliebigen +Stellen anzuhalten und den Zustand von Variablen sowie den Programmfluss zu +inspizieren. Moderne IDEs wie [Eclipse](https://eclipseide.org/) oder +[IntelliJ IDEA](https://www.jetbrains.com/idea/) verfügen über einen +integrierten Debugger. + +## Weiterführende Links + +Die folgenden Ressourcen bieten eine vertiefte Einführung in das Debugging mit +den gängigsten Java-IDEs. + +- [Eclipse Debugging Guide](https://www.eclipse.org/community/eclipse_newsletter/2017/june/article1.php) +- [IntelliJ IDEA – Debug Code](https://www.jetbrains.com/help/idea/debugging-code.html) +- [Visualizing Execution with Java Visualizer](https://pythontutor.com/java.html) + +## Breakpoints + +Ein _Breakpoint_ (Haltepunkt) markiert eine Zeile im Quellcode, an der die +Programmausführung pausiert werden soll. Sobald der Debugger die markierte Zeile +erreicht, hält er an – noch bevor die Anweisung in dieser Zeile ausgeführt wird. +Anschließend lassen sich Variablenwerte und der Aufrufstack inspizieren. + +```mermaid +flowchart LR + a[Programm im\nDebug-Modus starten] + b{Breakpoint\nerreicht?} + c[Ausführung\npausieren] + d[Zustand\ninspizieren] + e[Schritt\nausführen] + f[Programm\nendet] + + a --> b + b -- Nein --> f + b -- Ja --> c --> d --> e --> b +``` + +## Debug-Ansichten + +Beim Debuggen stehen in der IDE mehrere spezialisierte Ansichten zur Verfügung, +die gemeinsam ein vollständiges Bild des aktuellen Programmzustands liefern. + +| Ansicht | Beschreibung | +| ----------- | ---------------------------------------------------------------------------- | +| Variables | Zeigt alle aktuell sichtbaren Variablen und deren Werte | +| Breakpoints | Listet alle gesetzten Breakpoints und ermöglicht das Aktivieren/Deaktivieren | +| Call Stack | Zeigt die aktuelle Aufrufhierarchie der Methoden | +| Console | Gibt die Standardausgabe des laufenden Programms aus | +| Expressions | Wertet beliebige Ausdrücke im aktuellen Kontext aus | + +## Schrittweise Ausführung + +Nach dem Pausieren an einem Breakpoint stehen verschiedene Schritt-Befehle zur +Verfügung, um die Programmausführung gezielt fortzusetzen und den Kontrollfluss +zu verfolgen. + + + + +**Step Over** (`F6` in Eclipse / `F8` in IntelliJ) führt die aktuelle Zeile +vollständig aus und hält in der nächsten Zeile derselben Methode an. +Methodenaufrufe werden dabei als ein Schritt behandelt – der Debugger springt +nicht in die aufgerufene Methode hinein. + +```java title="Beispiel" showLineNumbers +int a = 5; // <- Debugger hält hier an +int b = add(a); // Step Over: add() wird ausgeführt, aber nicht betreten +int c = b * 2; // <- Debugger hält hier an nach Step Over +``` + + + + +**Step Into** (`F5` in Eclipse / `F7` in IntelliJ) springt in den Rumpf des +Methodenaufrufs in der aktuellen Zeile hinein, sodass dessen Ausführung Schritt +für Schritt verfolgt werden kann. + +```java title="Beispiel" showLineNumbers +int a = 5; // <- Debugger hält hier an +int b = add(a); // Step Into: Debugger springt in add() hinein +int c = b * 2; +``` + + + + +**Step Return** (`F7` in Eclipse / `Shift+F8` in IntelliJ) führt die restliche +aktuelle Methode vollständig aus und hält nach der Rückkehr in der aufrufenden +Methode an. Dieser Befehl wird typischerweise eingesetzt, wenn man versehentlich +in eine Methode hineingesprungen ist. + + + + +**Resume** (`F8` in Eclipse / `F9` in IntelliJ) setzt die Programmausführung +fort, bis der nächste Breakpoint erreicht wird oder das Programm regulär endet. + + + + +## Bedingte Breakpoints + +Ein _bedingter Breakpoint_ pausiert die Ausführung nur dann, wenn eine +angegebene Bedingung wahr ist. Das ist besonders nützlich, wenn ein Fehler nur +unter bestimmten Umständen auftritt – etwa bei einem konkreten +Schleifendurchlauf oder einem bestimmten Parameterwert. + +```java title="Example: Fehler tritt nur bei i == 42 auf" showLineNumbers +for (int i = 0; i < 100; i++) { + process(i); // <- bedingter Breakpoint: i == 42 +} +``` + +In Eclipse wird ein bedingter Breakpoint über **Rechtsklick auf den Breakpoint → +Breakpoint Properties → Enable Condition** gesetzt. In IntelliJ IDEA über +**Rechtsklick auf den Breakpoint → More → Condition**. + +## Häufige Fehler und deren Ursachen + +Die folgende Tabelle listet häufig auftretende Laufzeitausnahmen in Java und +deren typische Ursachen auf, um die Fehlersuche zu beschleunigen. + +| Ausnahme | Typische Ursache | +| -------------------------------- | ------------------------------------------------------------ | +| `NullPointerException` | Zugriff auf ein Objekt, das `null` ist | +| `ArrayIndexOutOfBoundsException` | Zugriff auf einen Index außerhalb der Array-Grenzen | +| `ClassCastException` | Ungültige Typumwandlung zur Laufzeit | +| `StackOverflowError` | Unendliche Rekursion | +| `NumberFormatException` | Ungültige Zeichenkette beim Parsen (z.B. `Integer.parseInt`) | diff --git a/docs/additional-material/tools/genai-tools.md b/docs/additional-material/tools/genai-tools.md index c759cde98f..3a431ae0f4 100644 --- a/docs/additional-material/tools/genai-tools.md +++ b/docs/additional-material/tools/genai-tools.md @@ -7,32 +7,25 @@ tags: [genai] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Generative KI (GenAI) bezeichnet KI-Systeme, die auf Grundlage neuronaler Netze -Inhalte wie Texte, Bilder, Videos, Musik, Quellcode etc. generieren können. -GenAI bildet damit die Grundlage für moderne Chatbots wie ChatGPT, Gemini oder -LeChat. Im Gegensatz zu "traditionellen" KI-Systemen, deren Aufgaben i.d.R. -darin bestehen, Muster zu erkennen, Daten zu klassifizieren oder Zusammenhänge -zu erkennen, kann GenAI mittels statistischer Wahrscheinlichkeiten und -tiefgreifender Mustererkennung neuartige Inhalte erzeugen, die nicht Teil der -Trainingsdaten waren. Schlüsselmodelle sind hierbei _Large Language Models_ -(LLMs) für Texte sowie Diffunsionsmodelle und _Generative Adversarial Networks_ -(GANs) für Bilder und Videos. Moderne Chatbots simulieren menschliche -Konversationen über Text und Sprache und nutzen dabei LLMs, um dynamisch, -kontextabhängig und zusammenhängend zu antworten. KI-gestützte Assistenzsysteme -(Co-Pilots) wie Microsoft 365 Copilot und GitHub Copilot dagegen sind direkt in -eine Anwendung (z.B. Textverarbeitungsprogramm, Tabellenkalkulationsprogramm, -IDE) integriert und unterstützen den menschlichen Anwender aktiv, ohne dabei die -Kontrolle zu übernehmen. Sie arbeiten quasi _parallel_ zum Anwender. +Generative KI (GenAI) bezeichnet KI-Systeme, die auf Basis neuronaler Netze +Inhalte wie Texte, Bilder, Videos, Musik oder Quellcode erzeugen. Im Unterschied +zu "traditionellen" KI-Systemen, die Muster erkennen oder Daten klassifizieren, +kann GenAI mittels statistischer Wahrscheinlichkeiten neuartige Inhalte +generieren, die nicht Teil der Trainingsdaten waren. Schlüsseltechnologien sind +_Large Language Models_ (LLMs) für Texte sowie Diffusionsmodelle und _Generative +Adversarial Networks_ (GANs) für Bilder und Videos. Moderne Chatbots wie +ChatGPT, Gemini oder LeChat nutzen LLMs, um kontextabhängig und zusammenhängend +zu antworten. KI-gestützte Assistenzsysteme (Co-Pilots) wie Microsoft 365 +Copilot oder GitHub Copilot sind dagegen direkt in eine Anwendung integriert und +unterstützen den Anwender aktiv, ohne die Kontrolle zu übernehmen. ## Prompt Engineering -Prompt Engineering ist die Disziplin der Entwicklung und Optimierung von -Eingaben (Prompts) mit dem Ziel, vorhersagbare, präzise und qualitativ -hochwertige Ausgaben von generativen Modellen zu bekommen, die den spezifischen -Anforderungen entsprechen. Die Grundprinzipien eines guten Prompts sind -Klarheit, Kontext und Struktur. Um die Qualität von Prompts zu erhöhen und damit -bessere, präzisere und zuverlässigere Ausgaben zu erhalten, können -unterschiedliche Techniken verwendet werden. +Prompt Engineering ist die Disziplin der gezielten Formulierung von Eingaben +(Prompts), um von einem generativen Modell vorhersagbare, präzise und +hochwertige Ausgaben zu erhalten. Ein guter Prompt zeichnet sich durch Klarheit, +Kontext und Struktur aus. Die folgenden Techniken helfen dabei, die Qualität von +Prompts zu verbessern. @@ -109,22 +102,17 @@ Wenn der Zug 20 Minuten Verspätung hat, wann kommt er in B an? ## Vibe Coding -Vibe Coding beschreibt eine neuartige Methode der Softwareentwicklung, bei der -ein LLM zur Generierung des benötigten Quellcodes genutzt wird. Der Begriff -wurde maßgeblich von OpenAI-Mitbegründer Andrej Karpathy geprägt und beschreibt -die entspannte Zusammenarbeit mit der KI, bei der sich der Softwareentwickler -voll und ganz auf den positiven Workflow und die inspirierende Atmosphäre mit -der KI einlässt. Im Unterschied zur herkömmlichen Softwareentwicklung, bei der -der Softwareentwickler selbst für das Erzeugen des Quellcodes zuständig ist, -steht beim Vibe Coding die klare Beschreibung der Funktionalität in natürlicher -Sprache durch Prompts im Vordergrund. Der konkrete Quellcode dagegen wird von -der LLM erzeugt. Es handelt sich daher im Kern um eine Anwendung des Prompt -Engineerings auf die Softwareentwicklung. Einsatzgebiete sind unter Anderem das -Rapid Prototyping, die Erstellung von _Minimal Viable Products_ (MVPs) sowie das -automatische Erzeugen von Boilerplate-Code. Nachteil von Vibe Coding ist vor -allem eine stark schwankende Softwarequalität und ein damit verbundener erhöhter -Wartungsaufwand. Es eignet sich daher nur bedingt für komplexe -Softwareanwendungen oder Softwareanwendungen mit einem hohen Qualitätsanspruch. +Vibe Coding ist eine Methode der Softwareentwicklung, bei der ein LLM den +Quellcode auf Basis natürlichsprachlicher Beschreibungen generiert. Der Begriff +wurde von OpenAI-Mitbegründer Andrej Karpathy geprägt. Im Unterschied zur +herkömmlichen Softwareentwicklung steht nicht das Schreiben von Code im +Vordergrund, sondern die klare Beschreibung der gewünschten Funktionalität durch +Prompts — das LLM übernimmt die Implementierung. Vibe Coding ist damit im Kern +eine Anwendung des Prompt Engineerings auf die Softwareentwicklung. +Einsatzgebiete sind unter anderem Rapid Prototyping, die Erstellung von _Minimal +Viable Products_ (MVPs) und das Erzeugen von Boilerplate-Code. Nachteil ist eine +oft schwankende Softwarequalität und ein erhöhter Wartungsaufwand — Vibe Coding +eignet sich daher nur bedingt für komplexe oder qualitätskritische Anwendungen. ```mermaid flowchart @@ -136,8 +124,7 @@ flowchart a --> b --> c --> d --> b ``` -Im Beispiel soll ein einfacher Taschenrechner mit Hilfe von JavaFX entwickelt -werden. +Im Beispiel soll ein einfacher Taschenrechner mit JavaFX entwickelt werden. diff --git a/docs/additional-material/tools/git.mdx b/docs/additional-material/tools/git.mdx index 24df2c6976..4de38017fd 100644 --- a/docs/additional-material/tools/git.mdx +++ b/docs/additional-material/tools/git.mdx @@ -8,23 +8,20 @@ tags: [git] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Git stellt eine Software zur Verwaltung von Dateien mit integrierter -Versionskontrolle dar, dessen Entwicklung unter Anderem von Linus Torvald (dem -Erfinder von Linux) initiiert wurde. Die Versionskontrolle von Git ermöglicht -den Zugriff auf ältere Entwicklungsstände, ohne dabei den aktuellen Stand zu -verlieren. Zudem unterstützt Git die Verwaltung von verteilten Dateien an -verschiedenen Aufbewahrungsorten. Diese Aufbewahrungsorte werden als -_Repositorys_ bezeichnet. Man unterscheidet dabei zwischen lokalen Repositorys -und remote Repositorys. Onlinedienste wie GitHub basieren auf Git und stellen -dem Anwender Speicherplatz für remote Repositorys zur Verfügung. +Git ist eine Software zur verteilten Versionskontrolle von Dateien. Entwickelt +wurde Git unter anderem von Linus Torvalds, dem Erfinder von Linux. Die +Versionskontrolle ermöglicht den Zugriff auf ältere Entwicklungsstände, ohne +dabei den aktuellen Stand zu verlieren. Dateien werden an sogenannten +_Repositorys_ abgelegt — entweder lokal auf dem eigenen Rechner oder auf einem +Remote-Server. Onlinedienste wie GitHub basieren auf Git und stellen +Speicherplatz für Remote-Repositorys bereit. ## Git Workflows -Aufgrund der Flexibilität von Git gibt es keine standardisierten Prozesse für -das Arbeiten mit Git. Ein Git Workflow stellt eine Anleitung zur Verwendung von -Git dar, die eine konsistente und produktive Arbeitsweise ermöglichen soll. Für -eine effiziente und fehlerfreie Arbeitsweise sollten daher alle Mitgleider eines -Teams die gleichen Git Workflows verwenden. +Ein Git Workflow ist eine Vereinbarung im Team darüber, wie Git genutzt wird. Er +legt fest, wann Commits erstellt, welche Branch-Strategien eingesetzt und wie +Änderungen synchronisiert werden. Einheitliche Workflows sind Voraussetzung für +eine effiziente und fehlerarme Zusammenarbeit. ```mermaid sequenceDiagram @@ -57,12 +54,10 @@ sequenceDiagram ## Git Befehle -Git bietet einen Vielzahl an verschiedenen Kommandozeilen-Befehlen um mit Git zu -arbeiten. Eine ausführliche Dokumentation der einzelnen Befehle samt der -dazugehörigen Optionen können auf der offiziellen -[Git-Homepage](https://git-scm.com/docs) gefunden werden. Zudem kann mit dem -Befehl `git --help` direkt in der Kommandozeile eine Kurzversion der -Dokumentation ausgegeben werden. +Git wird über Kommandozeilen-Befehle gesteuert. Die vollständige Dokumentation +aller Befehle und Optionen ist auf der offiziellen +[Git-Homepage](https://git-scm.com/docs) verfügbar. Mit `git --help` lässt sich +eine Kurzübersicht direkt in der Kommandozeile ausgeben. diff --git a/docs/additional-material/tools/markdown.mdx b/docs/additional-material/tools/markdown.mdx index 3b397650fd..29951a4606 100644 --- a/docs/additional-material/tools/markdown.mdx +++ b/docs/additional-material/tools/markdown.mdx @@ -8,17 +8,18 @@ tags: [markdown] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Markdown stellt eine einfache Auszeichnungssprache dar, mit der man Text leicht -formatieren kann. Sie wird häufig für Dokumentationen, README-Dateien und Blogs -verwendet, weil sie leicht zu schreiben ist und sich mit Hilfe einer -Konvertierungssoftware gut in HTML umwandeln lässt. Plattformen wie GitHub -erweitern dabei oftmals die Standard-Syntax um hilfreiche Funktionen wie z.B. -Tabellen, Nachrichtenblöcke und Code-Highlighting. Auch der Webseiten-Generator +Markdown ist eine einfache Auszeichnungssprache zum Formatieren von Text. Sie +wird häufig für Dokumentationen, README-Dateien und Blogs eingesetzt, da sie +leicht zu schreiben ist und sich gut in HTML umwandeln lässt. Plattformen wie +GitHub erweitern die Standardsyntax um Funktionen wie Tabellen, +Nachrichtenblöcke und Code-Highlighting. Auch [Docusaurus](https://docusaurus.io), mit dem diese Webseite erstellt wurde, sowie die meisten GenAI-Chatbots verwenden Markdown. ## Hilfreiche Links +Die folgenden Tools erleichtern das Arbeiten mit Markdown. + - [Tabellengenerator](https://www.tablesgenerator.com/) - [Emoji-Cheat-Sheet](https://github.com/ikatyang/emoji-cheat-sheet/) - [Quellcode-Formatierer](https://prettier.io/) @@ -26,6 +27,8 @@ sowie die meisten GenAI-Chatbots verwenden Markdown. ## Textformatierungen +Text lässt sich in Markdown mit wenigen Sonderzeichen formatieren. + | Syntax | Ergebnis | | ------------------------------ | --------------- | | `*Text*` oder `_Text_` | _Text_ | @@ -40,6 +43,9 @@ sowie die meisten GenAI-Chatbots verwenden Markdown. ## Überschriften +Überschriften werden mit Rauten (`#`) eingeleitet. Die Anzahl der Rauten +bestimmt die Hierarchieebene. + @@ -63,6 +69,9 @@ sowie die meisten GenAI-Chatbots verwenden Markdown. ## Links und Abbildungen +Links werden mit `[Anzeigetext](URL)` erstellt, Abbildungen mit +`![Alternativtext](URL)`. + @@ -84,6 +93,8 @@ sowie die meisten GenAI-Chatbots verwenden Markdown. ## Listen +Markdown unterstützt ungeordnete Listen, geordnete Listen und Aufgabenlisten. + @@ -130,6 +141,9 @@ sowie die meisten GenAI-Chatbots verwenden Markdown. ## Tabellen +Tabellen werden mit senkrechten Strichen (`|`) und Trennzeilen aus Bindestrichen +aufgebaut. + @@ -155,6 +169,9 @@ sowie die meisten GenAI-Chatbots verwenden Markdown. ## Codeblöcke +Codeblöcke werden mit drei Gravis (` ``` `) eingeleitet und abgeschlossen. +Optional kann die Programmiersprache für Syntax-Highlighting angegeben werden. + @@ -184,6 +201,8 @@ public class MainClass { ## Zitatblöcke +Zitatblöcke werden mit einem vorangestellten `>` eingeleitet. + @@ -204,6 +223,9 @@ public class MainClass { ## Nachrichtenblöcke +Nachrichtenblöcke heben wichtige Informationen visuell hervor. GitHub und +Docusaurus unterstützen unterschiedliche Syntaxvarianten. + @@ -300,11 +322,14 @@ Eine deutliche Warnung ## Mermaid-Diagramme +Mit Mermaid lassen sich Diagramme direkt im Markdown-Code beschreiben und +rendern. GitHub und Docusaurus unterstützen Mermaid nativ. + ```` -**Klassendiagram** +**Klassendiagramm** ```mermaid classDiagram Gender --o Person @@ -322,7 +347,7 @@ classDiagram ```` ```` -**Flussdiagram** +**Flussdiagramm** ```mermaid flowchart LR a[a] @@ -348,7 +373,7 @@ pie -**Klassendiagram** +**Klassendiagramm** ```mermaid classDiagram @@ -365,7 +390,7 @@ classDiagram } ``` -**Flussdiagram** +**Flussdiagramm** ```mermaid flowchart LR @@ -400,13 +425,16 @@ erstellen. ## Fußnoten +Fußnoten ermöglichen es, Quellenangaben oder ergänzende Hinweise ans Ende des +Dokuments auszulagern. + ``` Markdown [^1] -[^1]: Eine einfache Auszeichnungssprache (vg. https://de.wikipedia.org/wiki/Markdown) +[^1]: Eine einfache Auszeichnungssprache (vgl. https://de.wikipedia.org/wiki/Markdown) ``` @@ -423,6 +451,9 @@ Markdown [^1] ## Horizontale Linien +Eine horizontale Linie wird durch drei aufeinanderfolgende Bindestriche (`---`) +erzeugt. + diff --git a/docs/additional-material/tools/maven.md b/docs/additional-material/tools/maven.md index b99a183871..c4a20e7a80 100644 --- a/docs/additional-material/tools/maven.md +++ b/docs/additional-material/tools/maven.md @@ -7,35 +7,33 @@ tags: [maven] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -[Apache Maven (kurz Maven)](https://maven.apache.org/) ist ein sogenanntes -Build-Automatisierungstool, welches hauptsächlich für Java-Projekte verwendet -wird. Es hilft Entwicklern, den Build-Prozess eines Programmes zu vereinfachen -und zu standardisieren. Maven verwendet hierzu eine Konfigurationsdatei namens -_pom.xml_ (Project Object Model). +[Apache Maven (kurz Maven)](https://maven.apache.org/) ist ein +Build-Automatisierungstool für Java-Projekte. Es vereinfacht und standardisiert +den Build-Prozess über eine zentrale Konfigurationsdatei namens _pom.xml_ +(Project Object Model). ## Merkmale -- Automatisierung des Build-Prozesses: Maven automatisiert den Build-Prozess - (Kompilieren, Testen, Verpacken und Bereitstellen) -- Abhängigkeitsmanagement: Maven verwaltet Projekt-Abhängigkeiten wie externe - Bibliotheken und Frameworks automatisch -- Standardisierte Projektstruktur: Maven fördert eine standardisierte - Projektstruktur, die es einfacher macht, Projekte zu verstehen und zu - navigieren -- Plugins: Maven unterstützt eine Vielzahl von Plugins, die zusätzliche - Funktionalitäten bieten (z.B. Code-Analyse, Berichterstellung und - Dokumentation) -- Lebenszyklus-Management: Maven definiert einen standardisierten Lebenszyklus - für den Build-Prozess +Maven zeichnet sich durch folgende Eigenschaften aus: + +- Automatisierung des Build-Prozesses: Kompilieren, Testen, Verpacken und + Bereitstellen +- Abhängigkeitsmanagement: externe Bibliotheken und Frameworks werden + automatisch verwaltet +- Standardisierte Projektstruktur: erleichtert das Verstehen und Navigieren in + Projekten +- Plugins: erweitern Maven um zusätzliche Funktionen wie Code-Analyse, + Berichterstellung und Dokumentation +- Lebenszyklus-Management: definierter, standardisierter Ablauf des + Build-Prozesses ## Lebenszyklus-Phasen -Maven kennt die drei Lebenszyklen `clean` zum Löschen aller Artefakte -vergangener Builds, `default` zum Erstellen des Projekts sowie `site` zum -Erstellen einer Dokumentationsseite. Jeder Lebenszyklus durchläuft hierbei -verschiedene Phasen. Durch Plugins können diese um zusätzliche -Verarbeitungsschritte erweitert werden. Nachfolgend dargestellt sind die -wesentlichen Phasen des Default Lebenszyklus: +Maven kennt drei Lebenszyklen: `clean` löscht alle Artefakte vergangener Builds, +`default` erstellt das Projekt, und `site` generiert eine Dokumentationsseite. +Jeder Lebenszyklus durchläuft dabei mehrere Phasen, die sich durch Plugins um +zusätzliche Schritte erweitern lassen. Die folgende Tabelle zeigt die +wesentlichen Phasen des Default-Lebenszyklus. | Phase | Beschreibung | | ---------- | ------------------------------------------------------------------------------------ | @@ -49,11 +47,10 @@ wesentlichen Phasen des Default Lebenszyklus: ## Das Projektmodell -Das Projektmodel umfasst neben allgemeinen Projekt-Angaben wie der `groupId`, -der `artifactId` sowie der `version` auch sämtliche Abhängigkeiten zu externen -Bibliotheken, die dadurch automatisch von Maven verwaltet werden. Zudem kann -hier unter anderem der Build-Prozess konfiguriert und durch Plugins erweitert -werden. +Das Projektmodell enthält neben allgemeinen Projekt-Angaben wie `groupId`, +`artifactId` und `version` auch alle Abhängigkeiten zu externen Bibliotheken. +Zusätzlich lässt sich hier der Build-Prozess konfigurieren und durch Plugins +erweitern. ```xml title="pom.xml" showLineNumbers @@ -137,11 +137,11 @@ Berichtsseite. -[Prettier](https://prettier.io/) ist ein weit verbreiterter -Quellcode-Formatierer, der eine einheitliche Quellcode-Formatierung fördert. -Durch die Einbindung des Goals `write` in die Lebenszyklus-Phase `compile` wird +[Prettier](https://prettier.io/) ist ein weit verbreiteter +Quellcode-Formatierer, der eine einheitliche Formatierung fördert. Durch die +Einbindung des Goals `write` in die Lebenszyklus-Phase `compile` wird sichergestellt, dass der Quellcode bei jedem Kompiliervorgang automatisch -formattiert wird. +formatiert wird. ```xml title="pom.xml (Auszug)" showLineNumbers ... @@ -218,11 +218,16 @@ die Über-JAR bei jedem Verpacken erstellt wird. ## Hilfreiche Bibliotheken und Frameworks +Die folgende Auswahl an Bibliotheken und Frameworks wird häufig in +Java-Projekten eingesetzt und lässt sich einfach als Maven-Abhängigkeit +einbinden. + -Lombok ist eine beliebte Bibliothek zur Generierung von repetitiven Methoden -(siehe auch [Lombok](../../documentation/lombok)). +Lombok ist eine beliebte Bibliothek zur automatischen Generierung von +Boilerplate-Code wie Getter, Setter und Konstruktoren (siehe auch +[Lombok](../../documentation/lombok)). ```xml title="pom.xml (Auszug)" showLineNumbers ... @@ -240,11 +245,10 @@ Lombok ist eine beliebte Bibliothek zur Generierung von repetitiven Methoden -Simple Logging Facade for Java (SLF4J) ist eine beliebte -Java-Protokollierungs-API, die es ermöglicht, den Quellcode um Protokolle zu -erweitern, die anschließend an ein gewünschtes Protokoll-Framework (wie z.B. -Log4J) weitergeleitet werden (siehe auch -[Simple Logging Facade for Java (SLF4J)](../../documentation/slf4j)). +SLF4J (Simple Logging Facade for Java) ist eine Protokollierungs-API, die den +Quellcode von der konkreten Protokoll-Implementierung entkoppelt. Die +eigentlichen Protokollmeldungen werden an ein Framework wie Log4J weitergeleitet +(siehe auch [SLF4J](../../documentation/slf4j)). ```xml title="pom.xml (Auszug)" showLineNumbers ... @@ -309,8 +313,8 @@ das hauptsächlich für das Testen von Anwendungen verwendet wird (siehe auch -JavaFX stellt (vor allem in Verbindung mit Java FXML) ein State-of-the-Art -Framework für das Erstellen von GUIs in Java dar (siehe auch +JavaFX ist ein Framework für grafische Benutzeroberflächen in Java. In +Verbindung mit Java FXML lassen sich Layout und Logik sauber trennen (siehe auch [JavaFX](../../documentation/javafx)). ```xml title="pom.xml (Auszug)" showLineNumbers diff --git a/docs/documentation/abstract-and-final.mdx b/docs/documentation/abstract-and-final.mdx index 76bcf8b1eb..cb60b134fc 100644 --- a/docs/documentation/abstract-and-final.mdx +++ b/docs/documentation/abstract-and-final.mdx @@ -8,15 +8,14 @@ tags: [abstract, final] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Mit Hilfe der Schlüsselwörter `abstract` und `final` kann die Verwendung von -Klassen vorgegeben bzw. eingeschänkt werden: +Mit den Schlüsselwörtern `abstract` und `final` lässt sich die Verwendung von +Klassen und Methoden einschränken oder vorschreiben: - Abstrakte Klassen können nicht instanziiert werden -- Abstrakte Methoden werden in abstrakten Klassen definiert, besitzen dort - keinen Methodenrumpf und müssen in den abgeleiteten Klassen der abstrakten - Klasse überschrieben werden -- Finale Klassen können nicht abgeleitet werden -- Finale Methoden können nicht überschrieben werden +- Abstrakte Methoden werden in abstrakten Klassen deklariert, besitzen keinen + Methodenrumpf und müssen in allen abgeleiteten Klassen überschrieben werden +- Finale Klassen können nicht von anderen Klassen abgeleitet werden +- Finale Methoden können von Unterklassen nicht überschrieben werden @@ -50,7 +49,7 @@ public final class Notebook extends Computer { } @Override - public Cpu getCpu() {...} // Kompilierungsfehler + public Cpu getCpu() {...} // Kompilierungsfehler: finale Methode kann nicht überschrieben werden ... } ``` @@ -59,10 +58,10 @@ public final class Notebook extends Computer { ```java title="MainClass.java" showLineNumbers -public class MainClass extends Notebook { // Kompilierungsfehler +public class MainClass extends Notebook { // Kompilierungsfehler: finale Klasse kann nicht erweitert werden public static void main(String[] args) { - Computer computer = new Computer("Mein Office PC"); // Kompilierungsfehler + Computer computer = new Computer("Mein Office PC"); // Kompilierungsfehler: abstrakte Klasse kann nicht instanziiert werden } } diff --git a/docs/documentation/activity-diagrams.md b/docs/documentation/activity-diagrams.md index d11b58160c..085cd9219d 100644 --- a/docs/documentation/activity-diagrams.md +++ b/docs/documentation/activity-diagrams.md @@ -5,24 +5,20 @@ sidebar_position: 165 tags: [uml, activity-diagrams] --- -Aktivitätsdiagramme sind ein Diagrammtyp der UML und gehören dort zum Bereich -der Verhaltensdiagramme. Der Fokus von Aktivitätsdiagrammen liegt auf -imperativen Verarbeitungsaspekten. Eine Aktivität stellt einen gerichteten -Graphen dar, der über Knoten (Aktionen, Datenknoten und Kontrollknoten) und -Kanten (Kontrollflüsse und Datenflüsse) verfügt: +Aktivitätsdiagramme sind ein Diagrammtyp der UML und gehören zu den +Verhaltensdiagrammen. Sie modellieren den Ablauf von Aktivitäten mit Fokus auf +dem Kontroll- und Datenfluss. Eine Aktivität ist ein gerichteter Graph aus +Knoten und Kanten: -- Aktionen sind elementare Bausteine für beliebiges, benutzerdefiniertes - Verhalten -- Kontrollknoten steuern den Kontroll- und Datenfluss in einer Aktivität: - - Startknoten: legen den Beginn der Aktivität fest - - Endknoten: legen das Ende der Aktivität fest - - Ablaufendknoten: legen das Ende eines Ablaufes fest - - Verzweigungsknoten: ermöglichen die Verzweigung von Abläufen - - Zusammenführungsknoten: ermöglichen die Zusammenführung von Abläufen -- Datenknoten sind Hilfsknoten, die als ein- oder ausgehende Parameter einer - Aktion verwendet werden können -- Kontroll- und Datenflüsse legen Abläufe zwischen Vorgänger- und - Nachfolger-Knoten fest +- Aktionen sind elementare Bausteine für benutzerdefiniertes Verhalten. +- Kontrollknoten steuern den Ablauf: + - Startknoten legen den Beginn der Aktivität fest. + - Endknoten legen das Ende der Aktivität fest. + - Ablaufendknoten legen das Ende eines einzelnen Ablaufzweigs fest. + - Verzweigungsknoten ermöglichen das Aufteilen von Abläufen. + - Zusammenführungsknoten führen Abläufe wieder zusammen. +- Datenknoten dienen als ein- oder ausgehende Parameter einer Aktion. +- Kontroll- und Datenflüsse verbinden Vorgänger- und Nachfolgeknoten. ```mermaid stateDiagram-v2 diff --git a/docs/documentation/algorithms.mdx b/docs/documentation/algorithms.mdx index db8562f063..aec2dd0c9f 100644 --- a/docs/documentation/algorithms.mdx +++ b/docs/documentation/algorithms.mdx @@ -8,12 +8,10 @@ tags: [algorithms] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Ein Algorithmus stellt ein Verfahren zur Lösung eines Problems mit einer -endlichen Anzahl von Schritten dar. In der Prpgrammierung ist ein Algorithmus -eine Reihe von Anweisungen, die festlegen, was und wie etwas getan werden muss. -Zielsetzung ist dabei, aus einer gegebenen Eingabe eine entsprechende Ausgabe zu -erhalten. Beispiele aus der realen Welt für Algorithmen sind Aufbauanleitungen, -Rezepte, Spielanleitungen und Beipackzettel. +Ein Algorithmus ist ein schrittweises Verfahren zur Lösung eines Problems mit +einer endlichen Anzahl klar definierter Anweisungen. Er nimmt eine Eingabe +entgegen und liefert eine entsprechende Ausgabe. Alltagsbeispiele für +Algorithmen sind Kochrezepte, Aufbauanleitungen oder Beipackzettel. ```mermaid flowchart LR @@ -23,11 +21,11 @@ flowchart LR output[Ausgabe]@{ shape: lean-r } ``` -Das nachfolgende Rezept beschreibt die Zubereitung von Pankcakes: +Das nachfolgende Rezept beschreibt die Zubereitung von Pancakes: -1. 3 Eiweiss zu festem Eischnee verarbeiten -2. 3 Eigelb und 50g Zucker schaumig rühren -3. 300g Mehl, 300g Milch, 1 TL Backpulver und etwas Salz unter die +1. 3 Eiweiß zu festem Eischnee verarbeiten +2. 3 Eigelb und 50 g Zucker schaumig rühren +3. 300 g Mehl, 300 g Milch, 1 TL Backpulver und etwas Salz unter die Eigelb-Zuckermasse rühren 4. Sollte der Teig zu fest sein, zusätzlich Milch unterrühren 5. Den Eischnee unter den Teig heben @@ -44,34 +42,31 @@ ausführbares Programm bezeichnet man als Programmierung. ## Eigenschaften von Algorithmen -Damit ein Verfahren als Algorithmus angesehen werden kann, muss es verschiedene -Eigenschaften erfüllen: +Damit ein Verfahren als Algorithmus gilt, muss es die folgenden Eigenschaften +erfüllen: -- Determiniertheit: Ein Verfahren ist deterministisch, wenn es bei beliebig - häufiger Wiederholung für gleiche Eingabewerte und gleichen Rahmenbedingungen - immer zum gleichen Ergebnis führt. -- Eindeutigkeit (Determinismus): Ein Verfahren ist determiniert, wenn die - Schrittfolge immer gleich ist und immer zu einem eindeutigen Ergebnis führt. -- Endlichkeit (Terminiertheit): Ein Verfahren ist terministisch, wenn die Anzahl - der Schritte endlich ist, also wenn das Verfahren nach endlichen Schritten ein - Ergebnis liefert. -- Korrektheit: Ein Verfahren ist korrekt, wenn es immer zu einem richtigen - Ergebnis führt. +- Determiniertheit: Bei gleicher Eingabe und gleichen Rahmenbedingungen führt + der Algorithmus immer zum gleichen Ergebnis. +- Determinismus (Eindeutigkeit): Die Schrittfolge ist eindeutig festgelegt und + führt immer zu einem eindeutigen Ergebnis. +- Terminiertheit (Endlichkeit): Der Algorithmus endet nach einer endlichen + Anzahl von Schritten. +- Korrektheit: Der Algorithmus liefert für alle gültigen Eingaben das richtige + Ergebnis. ## Komplexität von Algorithmen -Da der Zeitaufwand von Algorithmen aufgrund unterschiedlicher Faktoren -(Hardware, parallele Verarbeitung, Eingabereihenfolge,…) nicht genau ermittelt -werden kann, wird diese mit Hilfe der Landau-Notation 𝒪 (_Ordnung von_) -dargestellt. Diese teilt Algorithmen in unterschiedliche Komplexitätsklassen -(logarithmisch, linear, polynomial,…) ein. Die Komplexität einer Klasse ergibt -sich dabei aus der Anzahl der Schritte, die abhängig von der Größe der -Eingangsvariablen ausgeführt werden müssen. +Da die Laufzeit eines Algorithmus von Faktoren wie Hardware, paralleler +Verarbeitung oder der Eingabereihenfolge abhängt, wird sie nicht absolut +gemessen, sondern mit der Landau-Notation 𝒪 (_Ordnung von_) beschrieben. Diese +teilt Algorithmen in Komplexitätsklassen ein (z.B. logarithmisch, linear, +polynomial) und gibt an, wie viele Schritte der Algorithmus in Abhängigkeit von +der Eingabegröße benötigt. ## Suchalgorithmen -Suchalgorithmen sollen innerhalb einer Datensammlung einen oder mehrere -Datensätze mit bestimmten Eigenschaften finden. +Suchalgorithmen finden innerhalb einer Datensammlung einen oder mehrere Einträge +mit bestimmten Eigenschaften. | Algorithmus | Komplexität Best Case | Komplexität Average Case | Komplexität Worst Case | | ------------------- | --------------------- | ------------------------ | ---------------------- | @@ -82,10 +77,10 @@ Datensätze mit bestimmten Eigenschaften finden. -Bei der Linearsuche werden alle Einträge einer Datensammlung nacheinander -durchlaufen, d.h. eine Suche kann im besten Fall beim ersten Eintrag und im -schlechtesten Fall beim letzten Eintrag beendet sein. Bei einer erfolglosen -Suche müssen alle Einträge durchlaufen werden. +Bei der Linearsuche werden alle Einträge der Datensammlung nacheinander +durchlaufen. Im besten Fall wird das gesuchte Element beim ersten Zugriff +gefunden, im schlechtesten Fall erst beim letzten. Bei einer erfolglosen Suche +werden alle Einträge durchlaufen. Im nachfolgenden Beispiel wird die Zahlenfolge `12, 16, 36, 49, 50, 68, 70, 76, 99` nach dem Wert 70 durchsucht. @@ -112,10 +107,10 @@ verbessert werden. -Bei der Binärsuche wird die sortierte Sammlung schrittweise halbiert. -Anschließend wird nur noch in der jeweils passenden Hälfte weitergesucht. Die -Binärsuche folgt damit dem Teile-und-Herrsche-Prinzip und ist i.d.R. schneller -als die Linearsuche, setzt aber eine sortierte Sammlung voraus. +Bei der Binärsuche wird die sortierte Sammlung schrittweise halbiert, und die +Suche wird nur in der passenden Hälfte fortgesetzt. Dieses Teile-und-Herrsche- +Prinzip macht die Binärsuche deutlich schneller als die Linearsuche, setzt aber +eine sortierte Sammlung voraus. Im nachfolgenden Beispiel wird die Zahlenfolge `12, 16, 36, 49, 50, 68, 70, 76, 99` nach dem Wert 70 durchsucht. @@ -154,10 +149,10 @@ Zahl ist, verwendet. -Die Interpolationssuche basiert auf der Binärsuche, halbiert die Sammlung aber -nicht, sondern versucht, durch Interpolation, einen geeigneteren Teiler zu -ermitteln. Dieser wird mit Hilfe der Formel -`t = ⌊𝑙 + ((𝑠 − 𝑑[𝑙]) / (𝑑[𝑟] − 𝑑[𝑙])) ∗ (𝑟 − 𝑙)⌋` ermittelt. +Die Interpolationssuche basiert auf der Binärsuche, berechnet den Teilungspunkt +jedoch nicht als Mitte, sondern durch Interpolation mit der Formel +`t = ⌊𝑙 + ((𝑠 − 𝑑[𝑙]) / (𝑑[𝑟] − 𝑑[𝑙])) ∗ (𝑟 − 𝑙)⌋`. Dadurch kann sie bei +gleichmäßig verteilten Daten schneller konvergieren. Im nachfolgenden Beispiel wird die Zahlenfolge `12, 16, 36, 49, 50, 68, 70, 76, 99` nach dem Wert 70 durchsucht. @@ -191,14 +186,12 @@ Teiler, ⌊ ⌋ = untere Gaußklammer ## Sortieralgorithmen -Sortieralgorithmen sollen eine möglichst effiziente Speicherung von Daten und -deren Auswertung ermöglichen. Man unterscheidet dabei zwischen einfachen und -rekursiven Sortieralgorithmen. Zusätzlich wird bei Sortierverfahren zwischen -stabilen und nichtstabilen Verfahren unterschieden. Bei stabilen -Sortierverfahren bleibt die Reihenfolge von gleich großen Datensätzen bei der -Sortierung erhalten. Die Platzkomplexität eines Sortierverfahrens schließlich -gibt an, ob zusätzlicher Speicherplatz für Zwischenergebnisse unabhängig von der -Anzahl Daten ist (_in-place_) oder nicht (_out-of-place_). +Sortieralgorithmen bringen eine Datensammlung in eine definierte Reihenfolge. +Man unterscheidet zwischen einfachen und rekursiven Verfahren sowie zwischen +stabilen (gleichwertige Elemente behalten ihre ursprüngliche Reihenfolge) und +nicht-stabilen Verfahren. Arbeitet ein Algorithmus ohne zusätzlichen +Speicherplatz aus, bezeichnet man ihn als _in-place_, andernfalls als +_out-of-place_. | Algorithmus | Komplexität Best Case | Komplexität Average Case | Komplexität Worst Case | Stabil | In-Place | | ------------- | --------------------- | ------------------------ | ---------------------- | ------ | -------- | @@ -212,10 +205,9 @@ Anzahl Daten ist (_in-place_) oder nicht (_out-of-place_). -Der Bubblesort verfolgt die Idee, das größere Blasen schneller aufsteigen als -kleinere. Dementsprechend werden beim Bubblesort Nachbarelemente miteinander -verglichen und gegebenenfalls vertauscht, so dass am Ende eines Durchlaufs das -jeweils größte Element am Ende des noch unsortierten Teils steht. +Beim Bubblesort werden benachbarte Elemente miteinander verglichen und bei +falscher Reihenfolge getauscht. Nach jedem Durchlauf steht das größte Element am +Ende des noch unsortierten Bereichs — ähnlich einer aufsteigenden Blase. | Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | | ----- | --- | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | @@ -232,10 +224,9 @@ jeweils größte Element am Ende des noch unsortierten Teils steht. -Beim Insertionsort wird dem unsortierten Teil der Ausgangsdaten ein beliebiges -Element entnommen (z.B. das jeweils erste) und an der richtigen Stelle im -sortierten Teil wieder eingefügt. Beim Einfügen wird das entnommene Element mit -den bereits sortierten Elementen verglichen. +Beim Insertionsort wird jeweils ein Element aus dem unsortierten Bereich +entnommen und an der richtigen Position im sortierten Bereich eingefügt. Das +Verfahren entspricht dem Sortieren von Spielkarten in der Hand. | Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | | ----- | --- | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | @@ -252,8 +243,8 @@ den bereits sortierten Elementen verglichen. -Beim Selectionsort wird dem unsortierten Teil der Ausgangsdaten das jeweils -kleinste Element entnommen und dem sortierten Teil angehängt. +Beim Selectionsort wird in jedem Durchlauf das kleinste Element aus dem +unsortierten Bereich gesucht und an das Ende des sortierten Bereichs angefügt. | Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | | ----- | --- | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | @@ -270,11 +261,10 @@ kleinste Element entnommen und dem sortierten Teil angehängt. -Beim Quicksort wird die jeweilige Sammlung anhand eines beliebigen Elements -(i.d.R. das mittlere Element) in zwei Hälften aufgeteilt: eine Hälfte mit -Elementen kleiner oder gleich dem Teiler-Element und eine Hälfte mit Elementen -größer dem Teiler-Element. Der Quicksort setzt folglich auf das -Teile-und-Herrsche-Prinzip. +Beim Quicksort wird ein Pivot-Element gewählt (in der Regel das mittlere +Element), und die Sammlung wird in zwei Teile aufgeteilt: Elemente kleiner oder +gleich dem Pivot und Elemente größer als das Pivot. Das Verfahren wird rekursiv +auf beide Teile angewendet (Teile-und-Herrsche-Prinzip). | Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | | ----- | ---- | ---- | ------ | ------ | ------ | ------ | ------ | @@ -315,9 +305,9 @@ Zahl ist, verwendet. -Beim Mergesort wird die Ausgangsliste zunächst in kleinere Listen zerlegt, die -anschließend im Reißverschlussverfahren wieder zusammengefügt bzw. verschmolzen -werden. +Beim Mergesort wird die Liste zunächst rekursiv in Einzelelemente zerlegt. +Anschließend werden die Teillisten im Reißverschlussverfahren sortiert +zusammengeführt (gemergt). ```mermaid flowchart @@ -369,12 +359,11 @@ flowchart -Beim Heapsort werden die Daten zunächst in einen binären Max-Heap überführt, -d.h. in einen Binärbaum, bei dem jeder Elternknoten größer ist als seine -Kindknoten. Anschließend wird in jedem Durchlauf das jeweils letzte Element mit -dem Wurzelknoten ausgetauscht und anschließend durch Vergleichen und Austauschen -sichergestellt, dass weiterhin alle Knoten die Heap-Bedingung erfüllen. Dieser -Schritt wird als Heapify oder Versickern bezeichnet. +Beim Heapsort werden die Daten zunächst in einen binären Max-Heap überführt — +einen Binärbaum, in dem jeder Elternknoten größer ist als seine Kindknoten. +Anschließend wird in jedem Durchlauf das größte Element (die Wurzel) entnommen +und durch das letzte Element ersetzt, woraufhin die Heap-Eigenschaft +wiederhergestellt wird (Heapify / Versickern). ```mermaid flowchart TD diff --git a/docs/documentation/array-lists.md b/docs/documentation/array-lists.md index f0508ac69a..ede6b630ec 100644 --- a/docs/documentation/array-lists.md +++ b/docs/documentation/array-lists.md @@ -5,10 +5,9 @@ sidebar_position: 141 tags: [collections, arrays, lists] --- -Um das Arbeiten mit Feldern zu erleichtern, stellt die Java API die Klasse -`ArrayList` zur Verfügung. Diese stellt eine veränderbare Liste dynamischer -Größe auf Basis eines Feldes dar und bietet hilfreiche Methoden zum Hinzufügen, -Ändern, Löschen und Lesen von Listelementen. +Die Klasse `ArrayList` aus der Java API stellt eine veränderbare Liste +dynamischer Größe auf Basis eines Feldes bereit und bietet Methoden zum +Hinzufügen, Ändern, Löschen und Lesen von Elementen. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -19,12 +18,28 @@ public class MainClass { names.add("Peter"); names.add("Lisa"); - System.out.println(names.size()); - System.out.println(names.get(0)); - names.set(0, "Max"); - names.add("Heidi"); - names.remove(0); + System.out.println(names.size()); // Anzahl der Elemente + System.out.println(names.get(0)); // Element an Index 0 lesen + names.set(0, "Max"); // Element an Index 0 ersetzen + names.add("Heidi"); // Element am Ende hinzufügen + names.remove(0); // Element an Index 0 entfernen } } ``` + +Die folgende Tabelle zeigt häufig verwendete Methoden der Klasse `ArrayList`. + +| Methode | Rückgabetyp | Beschreibung | +| ----------------------- | ----------- | --------------------------------------------------- | +| `add(e: E)` | `boolean` | Fügt ein Element am Ende hinzu | +| `add(index: int, e: E)` | `void` | Fügt ein Element an der angegebenen Position ein | +| `get(index: int)` | `E` | Gibt das Element an der angegebenen Position zurück | +| `set(index: int, e: E)` | `E` | Ersetzt das Element an der angegebenen Position | +| `remove(index: int)` | `E` | Entfernt das Element an der angegebenen Position | +| `remove(o: Object)` | `boolean` | Entfernt das erste Vorkommen des Objekts | +| `size()` | `int` | Gibt die Anzahl der Elemente zurück | +| `contains(o: Object)` | `boolean` | Prüft, ob das Objekt in der Liste enthalten ist | +| `indexOf(o: Object)` | `int` | Gibt den Index des ersten Vorkommens zurück | +| `isEmpty()` | `boolean` | Prüft, ob die Liste leer ist | +| `clear()` | `void` | Entfernt alle Elemente | diff --git a/docs/documentation/arrays.md b/docs/documentation/arrays.md index 090ad3f21a..78c6411737 100644 --- a/docs/documentation/arrays.md +++ b/docs/documentation/arrays.md @@ -5,10 +5,10 @@ sidebar_position: 110 tags: [arrays] --- -Wenn eine große Menge an Daten verarbeitet werden soll, kann man auf spezielle -Datenstruktur-Variablen, sogenannte _Felder_ (Arrays), zurückgreifen. Die -einzelnen Speicherplätze in einem Feld werden als Elemente bezeichnet, die über -einen Index angesprochen werden können. +Wenn eine größere Menge gleichartiger Daten verarbeitet werden soll, bieten sich +_Felder_ (Arrays) an. Ein Feld ist eine Datenstruktur, die eine feste Anzahl von +Elementen desselben Typs zusammenfasst. Die einzelnen Elemente werden über einen +nullbasierten Index angesprochen. | 0 | 1 | 2 | 3 | 4 | | ---- | ----- | ---- | --- | ----- | @@ -16,10 +16,10 @@ einen Index angesprochen werden können. ## Erzeugen von Feldern -Da es sich bei Feldern um Objekte handelt, müssen diese vor Verwendung erzeugt -werden. Bei der Erzeugung muss immer die Länge des Feldes (d.h. die Anzahl der -Elemente) angegeben werden. Jedes Feld verfügt über das Attribut `length`, -welches die Länge des Feldes enthält. +Da Felder Objekte sind, müssen sie vor der Verwendung mit dem `new`-Operator +erzeugt werden. Bei der Erzeugung muss die Länge des Feldes (Anzahl der +Elemente) angegeben werden. Jedes Feld besitzt das Attribut `length`, das die +Länge enthält. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -36,15 +36,15 @@ public class MainClass { :::info -Felder werden zwar mit Hilfe des new-Operators erzeugt, besitzen aber keinen +Felder werden zwar mit dem `new`-Operator erzeugt, besitzen aber keinen Konstruktor. ::: ## Zugriff auf Feldelemente -Der Zugriff auf die Elemente eines Feldes erfolgt über die Angabe des -entsprechenden Index. +Der Zugriff auf ein Element erfolgt über den zugehörigen Index in eckigen +Klammern. Der Index beginnt in Java bei 0. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -52,6 +52,7 @@ public class MainClass { public static void main(String[] args) { int[] ids = {4, 8, 15, 16, 23, 42}; + // alle Elemente über den Index ausgeben for (int i = 0; i < ids.length; i++) { System.out.println(ids[i]); } @@ -62,14 +63,14 @@ public class MainClass { :::info -Der Index beginnt bei Java bei 0. +Der Index beginnt in Java bei 0. ::: ## Der Parameter _String[] args_ -Der Parameter `String[] args` der main-Methode ermöglicht es dem Anwender, der -ausführbaren Klasse beim Aufruf Informationen mitzugeben. +Der Parameter `String[] args` der main-Methode ermöglicht es, der Anwendung beim +Aufruf über die Kommandozeile Argumente zu übergeben. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -86,9 +87,9 @@ public class MainClass { ## Variable Argumentlisten (VarArgs) Variable Argumentlisten (VarArgs) ermöglichen die Definition von Methoden, denen -beliebig viele Werte eines Datentyps mitgegeben werden können. Die -Parameterliste einer Methode kann allerdings nur eine variable Argumentliste -beinhalten und diese muss immer am Ende der Parameterliste stehen. +eine beliebige Anzahl von Werten desselben Datentyps übergeben werden kann. Eine +Parameterliste darf nur eine VarArgs-Liste enthalten, und diese muss stets am +Ende der Parameterliste stehen. ```java title="MainClass.java" showLineNumbers public class MainClass { diff --git a/docs/documentation/binary-numbers.mdx b/docs/documentation/binary-numbers.mdx index e3c9669404..9f48687097 100644 --- a/docs/documentation/binary-numbers.mdx +++ b/docs/documentation/binary-numbers.mdx @@ -9,15 +9,14 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; Informationen wie Zahlen und Zeichen werden im Computer in Form von sogenannten -_Bits_ (Binary Digits) gespeichert. Ein Bit stellt dabei die kleinstmögliche -Informationseinheit dar und kann zwei Zustände einnehmen: 0 und 1 (bzw. "an" und -"aus", "wahr" und "falsch", "Strom fließt" und "Strom fließt nicht"). Zahlen, -die mit Hilfe von Bits dargestellt werden, bezeichnet man als Binärzahlen, das -dazugehörige Zahlensystem als Binärsystem. Zahlensysteme wie das Binärsystem -oder das Dezimalsystem legen fest, wie Zahlen dargestellt werden. Anhand des -Namens lässt sich dabei ableiten, wie viele Ziffern zur Darstellung einer Zahl -zur Verfügung stehen. Um Unklarheiten zu vermeiden, können Zahlen um einen nach- -und tiefgestellten Index ergänzt werden (2 = Binärsystem, 8 = Oktalsystem, 10 = +_Bits_ (Binary Digits) gespeichert. Ein Bit ist die kleinstmögliche +Informationseinheit und kann zwei Zustände annehmen: 0 und 1 (bzw. „an" und +„aus", „wahr" und „falsch", „Strom fließt" und „Strom fließt nicht"). Zahlen, +die mit Hilfe von Bits dargestellt werden, nennt man _Binärzahlen_, das +dazugehörige Zahlensystem _Binärsystem_. Zahlensysteme legen fest, wie Zahlen +dargestellt werden — der Name verrät dabei jeweils, wie viele Ziffern zur +Verfügung stehen. Um Verwechslungen zu vermeiden, können Zahlen mit einem nach- +und tiefgestellten Index versehen werden (2 = Binärsystem, 8 = Oktalsystem, 10 = Dezimalsystem, 16 = Hexadezimalsystem). @@ -33,8 +32,8 @@ Dezimalsystem, 16 = Hexadezimalsystem). :::info -Das höchstwertige Bit wird als _Most Significant Bit_ (MSB), das niedrigstwertie -Bit als _Least Significant Bit_ (LSB) bezeichnet. +Das höchstwertige Bit wird als _Most Significant Bit_ (MSB), das +niedrigstwertige Bit als _Least Significant Bit_ (LSB) bezeichnet. ::: @@ -86,9 +85,9 @@ Notation bezeichnet wird, werden Zahlen als Produkt aus Mantisse und einer ## Größeneinheiten -Werden 8 Bits zu einer Einheit zusammengefasst, spricht man von einem _Byte_. -Werden 1.024 Byte wiederum zusammengefasst, spricht man von einem Kilobyte (KB) -bei 1.024 Kilobyte von einem Megabyte (MB) und so weiter. +Werden 8 Bits zu einer Einheit zusammengefasst, spricht man von einem _Byte_. Je +1.024 Bytes werden wiederum zu einem Kilobyte (KB) zusammengefasst, 1.024 +Kilobyte ergeben ein Megabyte (MB) und so weiter. | Einheit | Abkürzung | Größe in Byte | Größe in Bit | | -------- | --------- | ----------------- | -------------- | @@ -101,16 +100,15 @@ bei 1.024 Kilobyte von einem Megabyte (MB) und so weiter. ## Negative Binärzahlen -Da Binärzahlen keine Vorzeichen kennen, wird zur Darstellung von negativen -Binärzahlen ein Bit (in der Regel das MSB) als Vorzeichen genutzt, wobei die 0 -für eine positive Zahl, die 1 für eine negative Zahl steht. Verwendet man für -die Darstellung negativer Binärzahlen lediglich das Vorzeichenbit ergeben sich -allerdings Probleme wie eine doppelte Null sowie komplexe und ineffiziente -Rechenoperationen. Auch beim Einerkomplement (auch b-1-Komplement), bei dem alle -Bits der Binärzahl invertiert werden, bleiben diese Probleme (teils) bestehen. -Daher wird zu Darstellung negativer Dezimalzahlen das sogenannte -Zweierkomplement (auch b-Komplement) verwendet, bei welchem nach dem Invertieren -noch eine 1 hinzuaddiert wird. +Da Binärzahlen keine Vorzeichen kennen, wird zur Darstellung negativer Zahlen +ein Bit (in der Regel das MSB) als Vorzeichenbit genutzt: Die 0 steht für eine +positive, die 1 für eine negative Zahl. Verwendet man ausschließlich das +Vorzeichenbit, entstehen jedoch Probleme wie eine doppelte Null sowie komplexe +und ineffiziente Rechenoperationen. Auch beim _Einerkomplement_ +(b-1-Komplement), bei dem alle Bits invertiert werden, bleiben diese Probleme +teilweise bestehen. Daher wird in der Praxis das _Zweierkomplement_ +(b-Komplement) verwendet: Nach dem Invertieren aller Bits wird zusätzlich eine 1 +addiert. Im Beispiel wird die Zahl -5910 als negative Binärzahl dargestellt. @@ -123,8 +121,8 @@ Im Beispiel wird die Zahl -5910 als negative Binärzahl dargestellt. ## Reelle Binärzahlen -Die Darstellung reeller Binärzahlen erfolgt in Form von Gleitkommazahlen -(Floating Point Numbers). Diese ist in der Norm IEEE754 festgelegt. +Die Darstellung reeller Binärzahlen erfolgt als Gleitkommazahlen +(Floating-Point-Zahlen) gemäß der Norm IEEE 754. | | Datentyp | Größe | Vorzeichen | Exponent | Mantisse | Bias | | -------------------- | -------- | ------ | ---------- | -------- | -------- | ---- | @@ -140,7 +138,7 @@ Gleitkommazahlen können dabei spezielle Werte annehmen: - NaN (Not a Number): ungültige Werte (z.B. _Unendlich - Unendlich_) werden als NaN dargestellt -Im Beispiel wir die Zahl -156,3910 als Gleitkommazahl dargestellt. +Im Beispiel wird die Zahl -156,3910 als Gleitkommazahl dargestellt. | | Vorzeichen | Exponent | Mantisse | | -------------------- | ---------- | ----------- | ---------------------------------------------------- | diff --git a/docs/documentation/calculations.md b/docs/documentation/calculations.md index 9586cb1189..c3ef9ed0f6 100644 --- a/docs/documentation/calculations.md +++ b/docs/documentation/calculations.md @@ -5,9 +5,10 @@ sidebar_position: 70 tags: [java-api, math] --- -Die Klasse `Math` stellt neben einigen Konstanten wie der Kreiszahl _Pi_ und der -Eulerschen Zahl _E_ zahlreiche Methoden für mathematische Berechnungen zur -Verfügung. +Die Klasse `Math` aus dem Paket `java.lang` stellt neben den Konstanten +`Math.PI` (Kreiszahl π) und `Math.E` (Eulersche Zahl) zahlreiche Methoden für +mathematische Berechnungen bereit. Da alle Methoden statisch sind, müssen sie +nicht instanziiert werden. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -17,12 +18,30 @@ public class MainClass { int b = 3; double result; - result = Math.pow(a, b); + result = Math.pow(a, b); // a hoch b = 125.0 System.out.println(result); - result = Math.sqrt(a); + result = Math.sqrt(a); // Quadratwurzel aus a = 2.236... System.out.println(result); } } ``` + +Die folgende Tabelle zeigt häufig verwendete Methoden der Klasse `Math`. + +| Methode | Rückgabetyp | Beschreibung | +| -------------------------------- | ----------- | ------------------------------------------ | +| `abs(a: int)` | `int` | Gibt den Absolutbetrag zurück | +| `max(a: int, b: int)` | `int` | Gibt den größeren der beiden Werte zurück | +| `min(a: int, b: int)` | `int` | Gibt den kleineren der beiden Werte zurück | +| `pow(base: double, exp: double)` | `double` | Berechnet base hoch exp | +| `sqrt(a: double)` | `double` | Berechnet die Quadratwurzel | +| `round(a: double)` | `long` | Rundet auf die nächste ganze Zahl | +| `floor(a: double)` | `double` | Rundet ab (in Richtung −∞) | +| `ceil(a: double)` | `double` | Rundet auf (in Richtung +∞) | +| `log(a: double)` | `double` | Berechnet den natürlichen Logarithmus | +| `log10(a: double)` | `double` | Berechnet den dekadischen Logarithmus | +| `sin(a: double)` | `double` | Berechnet den Sinus (Winkel in Bogenmaß) | +| `cos(a: double)` | `double` | Berechnet den Kosinus (Winkel in Bogenmaß) | +| `tan(a: double)` | `double` | Berechnet den Tangens (Winkel in Bogenmaß) | diff --git a/docs/documentation/cases.md b/docs/documentation/cases.md index 8080c2bc70..155b08b90b 100644 --- a/docs/documentation/cases.md +++ b/docs/documentation/cases.md @@ -5,18 +5,17 @@ sidebar_position: 95 tags: [control-structures, cases] --- -Mit Hilfe von Verzweigungen (auch _Bedingte Anweisungen_ genannt) und -Fallunterscheidungen können unterschiedliche Anweisungsblöcke ausgeführt werden. -Verzweigungen und Fallunterscheidungen sind - genau wie Schleifen - wesentliche -Bestandteile der Programmierung un werden auch als _Kontrollstrukturen_ -bezeichnet. +Mit Hilfe von Verzweigungen (auch _bedingte Anweisungen_ genannt) und +Fallunterscheidungen können unterschiedliche Anweisungsblöcke abhängig von +Bedingungen ausgeführt werden. Verzweigungen und Fallunterscheidungen sind — +genau wie Schleifen — wesentliche Bestandteile der Programmierung und werden +zusammenfassend als _Kontrollstrukturen_ bezeichnet. ## Einfache Verzweigungen -Die if-Verzweigung ist eine Anweisung, die abhängig von einer Bedingung zwischen -unterschiedlichen Anweisungsblöcken auswählt: Ist die Bedingung wahr, wird der -Anweisungsblock direkt nach der Bedingung ausgeführt, ansonsten wird der -Anweisungsblock nach `else` ausgeführt. +Die if-Verzweigung wählt abhängig von einer Bedingung zwischen zwei +Anweisungsblöcken: Ist die Bedingung wahr, wird der Anweisungsblock direkt nach +der Bedingung ausgeführt, andernfalls der Anweisungsblock nach `else`. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -44,9 +43,8 @@ Der else-Zweig ist optional, kann also weggelassen werden. ## Mehrfachverzweigungen -Mehrfachverzweigungen können mit Hilfe einer if-else-if-Leiter abgebildet -werden. Die if-else-if-Leiter verschachtelt mehrere if-Anweisungen zu einer -sogenannten kaskadierten Verzweigung. +Mehrfachverzweigungen werden mit einer if-else-if-Leiter abgebildet, die mehrere +if-Anweisungen zu einer kaskadierten Verzweigung zusammenfasst. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -72,9 +70,9 @@ public class MainClass { ## Bedingte Zuweisungen -Wird eine if-Verzweigung für eine Wertzuweisung verwendet, spricht man von einer -bedingten Zuweisung. Zusätzlich zur ausführlichen Schreibweise existiert für -bedingte Zuweisungen auch eine Kurzschreibweise. +Wird eine if-Verzweigung ausschließlich für eine Wertzuweisung verwendet, +spricht man von einer bedingten Zuweisung. Neben der ausführlichen Schreibweise +gibt es dafür auch eine kompakte Kurzschreibweise mit dem Ternäroperator `?:`. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -84,7 +82,7 @@ public class MainClass { int y = 2; int z; - /* ausführliche Schreibweise */ + // ausführliche Schreibweise if (x > y) { z = 3; } else { @@ -92,7 +90,7 @@ public class MainClass { } System.out.println(z); - /* Kurzschreibweise */ + // Kurzschreibweise mit dem Ternäroperator z = (x > y) ? 3 : 4; System.out.println(z); } @@ -109,11 +107,11 @@ Lesbarkeit dadurch eventuell erschwert wird. ## Fallunterscheidungen -Fallunterscheidungen können entweder mit Hilfe von if-else-if-Leitern oder mit -Hilfe der switch-case-Anweisung realisiert werden. Tritt ein Fall ein, werden -alle Anweisungen bis zum nächsten `break` ausgeführt. Durch Weglassen von -`break` können unterschiedliche Fälle gleich behandelt werden. Der default-Block -wird immer dann ausgeführt, wenn keiner der aufgeführten Fälle eintritt. +Fallunterscheidungen können entweder mit einer if-else-if-Leiter oder mit der +switch-case-Anweisung umgesetzt werden. Tritt ein Fall ein, werden alle +Anweisungen bis zum nächsten `break` ausgeführt. Durch das Weglassen von `break` +können mehrere Fälle gleich behandelt werden. Der `default`-Block wird +ausgeführt, wenn keiner der aufgeführten Fälle zutrifft. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -141,8 +139,8 @@ public class MainClass { } ``` -Seit Java 14 beheben Switch-Ausdrücke einige Ungereimtheiten der klassischen -switch-case-Anweisung und ermöglichen eine elegantere Syntax. +Seit Java 14 vereinfachen Switch-Ausdrücke die Syntax und beheben einige +Schwächen der klassischen switch-case-Anweisung. ```java title="MainClass.java" showLineNumbers public class MainClass { diff --git a/docs/documentation/class-structure.mdx b/docs/documentation/class-structure.mdx index ed65c8bea9..2f5b17c459 100644 --- a/docs/documentation/class-structure.mdx +++ b/docs/documentation/class-structure.mdx @@ -9,13 +9,13 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; Klassen stellen den grundlegenden Rahmen für Programme dar. Jede Klasse kann -Daten (_Attribute_) und Routinen (_Methoden_) besitzen. Routinen bestehen dabei -aus Folgen von verzweigten und sich wiederholenden Anweisungen, wobei -Anweisungen wohldefinierte Befehle darstellen, die der Interpreter zur Laufzeit -ausführt. Anweisungen müssen in Java mit dem Semikolon abgeschlossen werden und -können zu Anweisungsblöcken zusammengefasst werden, die durch geschweifte -Klammern umschlossen werden. Innerhalb eines Anweisungsblocks können sich -weitere Anweisungsblöcke befinden. +Daten (_Attribute_) und Routinen (_Methoden_) besitzen. Routinen bestehen aus +Folgen von verzweigten und sich wiederholenden Anweisungen, wobei Anweisungen +wohldefinierte Befehle darstellen, die der Interpreter zur Laufzeit ausführt. +Anweisungen müssen in Java mit einem Semikolon abgeschlossen werden und können +zu Anweisungsblöcken zusammengefasst werden, die durch geschweifte Klammern +umschlossen sind. Innerhalb eines Anweisungsblocks können weitere +Anweisungsblöcke enthalten sein. @@ -70,7 +70,7 @@ public class MainClass { Statische Methoden sind abgeschlossene Programmteile, die Parameter enthalten und einen Wert zurückgeben können. Sie müssen mit dem Schlüsselwort `static` gekennzeichnet werden. Bei statischen Methoden, die einen Wert zurückgeben, muss -der Datentyp des Rückgabewertes angegeben werden; bei statische Methoden, die +der Datentyp des Rückgabewerts angegeben werden; bei statischen Methoden, die keinen Wert zurückgeben, das Schlüsselwort `void`. Der Aufruf einer statischen Methode erfolgt über den Klassennamen gefolgt von einem Punkt. diff --git a/docs/documentation/classes.md b/docs/documentation/classes.md index 9d38ab1a61..e8b78c4ec7 100644 --- a/docs/documentation/classes.md +++ b/docs/documentation/classes.md @@ -5,14 +5,13 @@ sidebar_position: 131 tags: [oo] --- -Klassen legen die Eigenschafen (Attribute) sowie das Verhalten (Methoden) von -Objekten fest und stellen damit quasi Baupläne für Objekte dar. +Klassen legen die Eigenschaften (Attribute) sowie das Verhalten (Methoden) von +Objekten fest und stellen damit Baupläne für Objekte dar. ## Sichtbarkeit von Klassen, Attributen und Methoden -Um die Sichtbarkeit von Klassen, Attributen und Methoden zu definieren, -existieren verschiedene Zugriffsrechte. Die Sichtbarkeit bestimmt, von welchem -Ort aus Klassen, Attribute und Methoden verwendet bzw. aufgerufen werden dürfen. +Über _Zugriffsrechte_ wird festgelegt, von welchem Ort aus auf Klassen, +Attribute und Methoden zugegriffen werden darf. | Zugriffsrecht | Zugriff aus gleicher Klasse | Zugriff von einer Klasse aus dem gleichen Paket | Zugriff von einer Unterklasse | Zugriff von einer beliebigen Klasse | | ------------- | --------------------------- | ----------------------------------------------- | ----------------------------- | ----------------------------------- | @@ -23,11 +22,11 @@ Ort aus Klassen, Attribute und Methoden verwendet bzw. aufgerufen werden dürfen ## Definition von Attributen -Die Attribute einer Klasse sind Datenobjekte und werdern daher analog zu -Variablen und Konstanten definiert. Das Schlüsselwort `final` erlaubt die -Definition von unveränderlichen Attributen, also Attributen, deren Wert nicht -geändert werden kann. Die Initialisierung dieser unveränderlichen Attribute -erfolgt durch [Konstruktoren](classes#definition-von-konstruktoren). +Die Attribute einer Klasse sind Datenobjekte und werden daher analog zu +Variablen und Konstanten definiert. Mit dem Schlüsselwort `final` lassen sich +unveränderliche Attribute definieren, deren Wert nach der Initialisierung nicht +mehr geändert werden kann. Die Initialisierung dieser Attribute erfolgt im +[Konstruktor](classes#definition-von-konstruktoren). ```java title="Computer.java (Auszug)" showLineNumbers public class Computer { @@ -48,17 +47,16 @@ Die Selbstreferenz `this` verweist innerhalb einer Klasse auf das eigene Objekt ## Definition und Implementierung von Methoden -Methoden sind in der Programmierung eine Verallgemeinerung von mathematischen -Funktionen. Eine Methode besteht aus einem Methodennamen, einer Liste von -Eingabeparameter (optional), einem Rückgabewert (optional) sowie dem -Methodenrumpf. Die Kombination aus Methodenname und den Datentypen der -Parameterliste bezeichent man als _Signatur einer Methode_. +Methoden sind in der Programmierung eine Verallgemeinerung mathematischer +Funktionen. Eine Methode besteht aus einem Namen, einer (optionalen) Liste von +Eingabeparametern, einem (optionalen) Rückgabewert sowie dem Methodenrumpf. Die +Kombination aus Methodenname und den Datentypen der Parameterliste bezeichnet +man als _Signatur_. -Methoden können entweder genau einen Rückgabewert oder keinen Rückgabewert -besitzen. Methoden mit genau einem Rückgabewert müssen vor dem Methodennamen den -Datentyp des Rückgabewerts angeben und am Ende des Methodenrumpfes immer die -Anweisung `return` besitzen, Methoden ohne Rückgabewert müssen dies mit dem -Schlüsselwort `void` kenntlich machen. +Methoden können entweder genau einen Rückgabewert oder keinen besitzen. Methoden +mit einem Rückgabewert müssen vor dem Methodennamen den Rückgabetyp angeben und +im Methodenrumpf eine `return`-Anweisung enthalten. Methoden ohne Rückgabewert +werden mit `void` gekennzeichnet. ```java title="Computer.java (Auszug)" showLineNumbers public class Computer { @@ -88,10 +86,10 @@ public class Computer { ## Definition überladener Methoden -Gleichnamige Methoden mit unterschiedlichen Parameterlisten einer Klasse werden -als überladene Methoden bezeichnet. Man spricht in diesem Zusammenhang auch von -statischer Polymorphie, da der Aufruf gleichnamiger Methoden unterschiedliche -Ergebnisse liefern kann. +Gleichnamige Methoden mit unterschiedlichen Parameterlisten in einer Klasse +werden als _überladene Methoden_ bezeichnet. Dieses Konzept nennt man auch +_statische Polymorphie_, da der Aufruf gleichnamiger Methoden je nach Parametern +zu unterschiedlichen Ergebnissen führt. ```java title="Computer.java (Auszug)" showLineNumbers public class Computer { @@ -115,17 +113,14 @@ public class Computer { ## Definition von Konstruktoren -Bei Konstruktoren handelt es sich um spezielle Methoden, die zur Initialisierung -eines Objekts verwendet werden. Konstruktoren heißen wie ihre Klasse und können -eine beliebige Anzahl an Parametern haben. Allerdings kann für Konstruktoren -kein Rückgabewert festgelegt werden, da diese implizit die Referenz auf das -Objekt zurückgeben. +Konstruktoren sind spezielle Methoden, die zur Initialisierung eines Objekts +dienen. Sie tragen denselben Namen wie ihre Klasse und können beliebig viele +Parameter haben. Ein Rückgabetyp wird nicht angegeben, da Konstruktoren implizit +eine Referenz auf das neue Objekt zurückgeben. -Im Gegensatz zu z.B. C++ existieren in Java keine Destruktoren, die nicht mehr -benötigte Objekte aus dem Speicher entfernen. Stattdessen läuft im Hintergrund -der sogenannte Garbage Collector, der nicht mehr benötigte Objekte (also -Objekte, die nicht mehr über eine Referenzvariable angesprochen werden können) -löscht. +Im Gegensatz zu z.B. C++ gibt es in Java keine Destruktoren. Stattdessen +übernimmt der _Garbage Collector_ im Hintergrund das Aufräumen: Er entfernt +Objekte aus dem Speicher, auf die keine Referenzvariable mehr zeigt. ```java title="Computer.java (Auszug)" showLineNumbers public class Computer { @@ -145,24 +140,22 @@ public class Computer { :::info -Auch Konstruktoren können überladen werden, das heißt eine Klasse kann über -mehrere Konstruktoren verfügen. Der Aufruf eines Konstruktors innerhalb eines -anderen Konstruktors erfolgt dabei über die Selbstreferenz `this`. +Auch Konstruktoren können überladen werden, d.h. eine Klasse kann über mehrere +Konstruktoren verfügen. Ein Konstruktor kann dabei einen anderen Konstruktor +derselben Klasse mit `this(...)` aufrufen. ::: ## Definition statischer Attribute und Methoden -Neben "normalen" Attributen und Methoden kann eine Klasse auch statische -Attribute und statische Methoden besitzen. Im Gegensatz zu "normalen" Attributen -existieren statische Attribute nur einmal pro Klasse und besitzen daher für alle -Objekte dieser Klasse dieselben Werte. Innerhalb einer statischen Methode kann -nur auf die statischen Attribute der Klasse zugegriffen werden. +Neben Instanzattributen und -methoden kann eine Klasse auch statische Attribute +und Methoden besitzen. Statische Attribute existieren nur einmal pro Klasse und +haben für alle Objekte dieser Klasse denselben Wert. Innerhalb einer statischen +Methode kann nur auf statische Attribute zugegriffen werden. -Bei der Deklaration von statischen Attributen und statischen Methoden kommt das -Schlüsselwort `static` zum Einsatz. Für den Zugriff auf ein statisches Attribut -bzw. den Aufruf einer statischen Methode wird keine Instanziierung benötigt, -d.h. der der Zugriff bzw. Aufruf erfolgt über den Klassennamen. +Statische Attribute und Methoden werden mit dem Schlüsselwort `static` +deklariert. Für den Zugriff ist keine Instanziierung nötig — er erfolgt direkt +über den Klassennamen. ```java title="Computer.java (Auszug)" showLineNumbers public class Computer { @@ -183,8 +176,7 @@ public class Computer { :::info -"Normale" Attribute und Methoden werden auch als Instanzattribute bzw. -Instanzmethoden bezeichnet, statische Attribute und Methoden auch -Klassenattribute bzw. Klassenmethoden. +Instanzattribute und -methoden werden auch als Klassenattribute und +Klassenmethoden bezeichnet, wenn sie statisch sind. ::: diff --git a/docs/documentation/coding.mdx b/docs/documentation/coding.mdx index 5608e90a16..6597d880dd 100644 --- a/docs/documentation/coding.mdx +++ b/docs/documentation/coding.mdx @@ -9,9 +9,9 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; Als ein Teilbereich der Softwareentwicklung umfasst das Programmieren vor allem -die Umsetzung eines Softwareentwurfes in Quellcode. Generell versteht man unter +die Umsetzung eines Softwareentwurfs in Quellcode. Allgemein versteht man unter Programmieren die Umsetzung von [Algorithmen](algorithms) in lauffähige -Computer-Programme. +Programme. ```mermaid flowchart LR @@ -26,38 +26,36 @@ Ein Algorithmus ist eine Handlungsvorschrift zur Lösung eines Problems. ## Abstraktionsniveau -Maschinen sind im Vergleich zu menschlichen Gehirnen sehr primitive Gebilde. Die +Maschinen sind im Vergleich zum menschlichen Gehirn sehr primitive Gebilde. Die Diskrepanz zwischen der menschlichen Denkweise und der Arbeitsweise von -Maschinen bezeichnet mal als _Semantische Lücke_. Programmiersprachen +Maschinen bezeichnet man als _Semantische Lücke_. Programmiersprachen ermöglichen es, Problemstellungen der realen Welt abstrahiert und -maschinengerecht abzubilden und damit die Semantische Lücke zu verringern. Je -höher die Abstraktion einer Programmiersprache dabei ist, desto mehr kann die -Semantische Lücke verringert werden: Maschinenorientierte Programmiersprachen -(z.B. X86-Assembler) abstrahieren kaum und sind daher für den Menschen schwerer -verständlich, problemorientierte Programmiersprachen (z.B. Java) abstrahieren -stark und sind daher für den Menschen leichter verständlich. - -| | Generation | Merkmale | Sprachen | -| ---------------- | ------------------------------ | ------------------------------------------ | ------------------------------------------- | -| Höhere Sprachen | 5: Sprachen der KI | Logik- und Regelbasiert | Lisp, Prolog | -| Höhere Sprachen | 4: Anwendungsbezogene Sprachen | Domänenspezifisch | SQL | -| Höhere Sprachen | 3: Problemorientierte Sprachen | Datenobjekte, Routinen, Kontrollstrukturen | C, C++, C#, Java, JavaScript, Python | -| Niedere Sprachen | 2: Assemblersprachen | Symbolische Befehle | X86-Assembler, MIPS-Asembler, ARM-Assembler | -| Niedere Sprachen | 1: Maschinensprache | Binärcode | - | +maschinengerecht abzubilden und damit diese Lücke zu verringern. Je höher die +Abstraktion einer Programmiersprache ist, desto mehr lässt sich die Semantische +Lücke verringern: Maschinenorientierte Sprachen (z.B. x86-Assembler) +abstrahieren kaum und sind daher für den Menschen schwerer verständlich, +problemorientierte Sprachen (z.B. Java) abstrahieren stark und sind daher +deutlich leichter verständlich. + +| | Generation | Merkmale | Sprachen | +| ---------------- | ------------------------------ | ------------------------------------------ | -------------------------------------------- | +| Höhere Sprachen | 5: Sprachen der KI | Logik- und Regelbasiert | Lisp, Prolog | +| Höhere Sprachen | 4: Anwendungsbezogene Sprachen | Domänenspezifisch | SQL | +| Höhere Sprachen | 3: Problemorientierte Sprachen | Datenobjekte, Routinen, Kontrollstrukturen | C, C++, C#, Java, JavaScript, Python | +| Niedere Sprachen | 2: Assemblersprachen | Symbolische Befehle | X86-Assembler, MIPS-Assembler, ARM-Assembler | +| Niedere Sprachen | 1: Maschinensprache | Binärcode | - | ## Programmierparadigmen Unter einem Programmierparadigma versteht man die grundlegende Herangehensweise, -Probleme mit Hilfe einer Programmiersprache zu lösen. Aber auch wenn -Programmiersprachen oft anhand ihrer grundlegenden Merkmale genau einem -Programmierparadigma zugeordnet werden, unterstützen viele Programmiersprachen -mehrere Programmierparadigmen. Generell werden die verschiedenen -Programmierparadigmen oft in zwei große Kategorien eingeteilt: bei imperativen -Programmierparadigmen steht die Frage _Wie soll das Ergebnis erreicht werden?_ -im Vordergrund, bei deklarativen Programmierparadigmen die Frage _Was soll das -Ergebnis sein?_. Imperative Programmierparadigmen legen also Schritt für Schritt -fest, wie das Ergebnis erreicht werden soll, deklarative Programmierparadigmen -beschreiben das Ergebnis selbst. +Probleme mit Hilfe einer Programmiersprache zu lösen. Viele Programmiersprachen +unterstützen dabei mehrere Paradigmen gleichzeitig, auch wenn sie oft einem +bestimmten Paradigma zugeordnet werden. Generell werden Programmierparadigmen in +zwei große Kategorien eingeteilt: Bei _imperativen_ Paradigmen steht die Frage +_Wie soll das Ergebnis erreicht werden?_ im Vordergrund, bei _deklarativen_ +Paradigmen die Frage _Was soll das Ergebnis sein?_ Imperative Paradigmen legen +also Schritt für Schritt fest, wie ein Ergebnis erreicht wird; deklarative +Paradigmen beschreiben stattdessen das gewünschte Ergebnis. | Programmierparadigmen | Kategorie | Fokus | Beispielsprachen | | -------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | @@ -68,17 +66,16 @@ beschreiben das Ergebnis selbst. ## Programmausführung -Programme auf einem Computer können auf unterschiedliche Arten ausgeführt -werden: Compilersprachen übersetzen den Quellcode in eine Datei, die vom -jeweiligen Betriebssystem ausgeführt werden kann, Interpretersprachen übersetzen -den Quellcode direkt in den Arbeitsspeicher und führen das Programm sofort aus -und Just-In-Time Compilersprachen (JIT) übersetzen den Quellcode mit Hilfe eines -Compilers zunächst in den sogenannten Bytecode und übersetzen diesen bei der -Ausführung in den Arbeitsspeicher. Compilersprachen wie C und C++ sind dabei -deutlich performanter und ermöglichen eine sicherere Entwicklung, -Interpretersprachen wie JavaScript und Python sind dagegen plattformunabhängig -und Just-In-Time Compliersprachen wie C# und Java vereinen die Vorteile beider -Welten. +Programme können auf einem Computer auf unterschiedliche Arten ausgeführt +werden. Bei _Compilersprachen_ wird der Quellcode vor der Ausführung vollständig +in eine ausführbare Datei übersetzt. Bei _Interpretersprachen_ wird der +Quellcode zur Laufzeit direkt ausgeführt, ohne vorherige Übersetzung. +_Just-In-Time- Compilersprachen_ (JIT) kombinieren beide Ansätze: Der Quellcode +wird zunächst in einen plattformunabhängigen Bytecode kompiliert, der dann zur +Laufzeit ausgeführt wird. Compilersprachen wie C und C++ sind dabei besonders +performant, Interpretersprachen wie JavaScript und Python sind +plattformunabhängig und JIT-Sprachen wie C# und Java vereinen die Vorteile +beider Ansätze. diff --git a/docs/documentation/comparators.md b/docs/documentation/comparators.md index 4dcbde1592..0a1faa4b79 100644 --- a/docs/documentation/comparators.md +++ b/docs/documentation/comparators.md @@ -5,14 +5,14 @@ sidebar_position: 220 tags: [comparators] --- -Mit Hilfe der Methode `int compareTo(o: T)` der Schnittstelle `Comparable` -bzw. der Methode `int compare(o1: T, o2: T)` der Schnittstelle `Comparator` -können Objekte einer Klasse miteinander verglichen werden. Der Rückgabewert -beider Methoden gibt die Ordnung der zu vergleichenden Objekte an: +Mit der Methode `int compareTo(o: T)` der Schnittstelle `Comparable` bzw. der +Methode `int compare(o1: T, o2: T)` der Schnittstelle `Comparator` lassen +sich Objekte miteinander vergleichen. Der Rückgabewert gibt die relative Ordnung +der verglichenen Objekte an: -- Rückgabewert kleiner Null: das Vergleichsobjekt ist größer -- Rückgabewert gleich Null: beide Objekte sind gleich groß -- Rückgabewert größer Null: das Vergleichsobjekt ist kleiner +- Rückgabewert < 0: das erste Objekt ist kleiner als das zweite +- Rückgabewert = 0: beide Objekte sind gleichwertig +- Rückgabewert > 0: das erste Objekt ist größer als das zweite Objekte der Klasse `Notebook` können durch die Implementierung der Methode `int compareTo(o: T)` der Schnittstelle `Comparable` miteinander verglichen @@ -43,11 +43,10 @@ public class NotebookByPowerInGhzComparator implements Comparator { } ``` -In der main-Methode der Startklasse wird mit Hilfe der statischen Methode -`void sort(list: List)` der Klasse `Collections` eine Liste mit Objekten der -Klasse `Notebook` sortiert. Aufgrund der Implementierung der compareTo-Methode -wird die Liste zunächst absteigend nach dem Attribut `memoryInGb` sortiert. -Anschließend wird die Liste aufsteigend nach der Prozessorleistung sortiert. +In der main-Methode wird mit der statischen Methode `void sort(list: List)` +der Klasse `Collections` eine Liste von `Notebook`-Objekten sortiert. Zunächst +wird nach `memoryInGb` absteigend sortiert (gemäß `compareTo`), anschließend +nach Prozessorleistung aufsteigend (gemäß `NotebookByPowerInGhzComparator`). ```java title="MainClass.java" showLineNumbers public class MainClass { diff --git a/docs/documentation/console-applications.md b/docs/documentation/console-applications.md index 4fe952dda8..2a5ec8f808 100644 --- a/docs/documentation/console-applications.md +++ b/docs/documentation/console-applications.md @@ -5,9 +5,9 @@ sidebar_position: 90 tags: [console-applications] --- -Konsolenanwendungen sind Programme ohne eine grafische Benutzeroberfläche d.h. -die Steuerung sowie die Eingabe und Ausgabe erfolgen ausschließlich über -textuelle Anweisungen. +Konsolenanwendungen sind Programme ohne grafische Benutzeroberfläche. Die +Steuerung sowie die Ein- und Ausgabe erfolgen ausschließlich über textuelle +Anweisungen. ```mermaid flowchart @@ -17,25 +17,35 @@ flowchart ## Konsoleneingaben -Die Klasse `Scanner` im Paket `java.util` stellt Methoden zur Verfügung, um -Eingaben von der Konsole einzulesen und in entsprechende Datentypen umzuwandeln. +Die Klasse `Scanner` im Paket `java.util` stellt Methoden bereit, um Eingaben +von der Konsole einzulesen und in entsprechende Datentypen umzuwandeln. Dem +Konstruktor muss dazu der Standard-Eingabestrom `System.in` übergeben werden. ```java title="MainClass.java" showLineNumbers public class MainClass { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); - int i = scanner.nextInt(); + int i = scanner.nextInt(); // ganze Zahl einlesen System.out.println(i); } } ``` +Die folgende Tabelle zeigt häufig verwendete Methoden der Klasse `Scanner`. + +| Methode | Rückgabetyp | Beschreibung | +| --------------- | ----------- | ------------------------------------------------ | +| `nextInt()` | `int` | Liest die nächste ganze Zahl ein | +| `nextDouble()` | `double` | Liest die nächste Dezimalzahl ein | +| `nextBoolean()` | `boolean` | Liest den nächsten booleschen Wert ein | +| `next()` | `String` | Liest das nächste Wort ein (bis zum Leerzeichen) | +| `nextLine()` | `String` | Liest die nächste Zeile ein | + :::info -Dem Konstruktor muss der Standard-Eingabestrom `System.in` als Wert mitgegeben -werden. +Dem Konstruktor muss der Standard-Eingabestrom `System.in` übergeben werden. ::: @@ -44,13 +54,10 @@ werden. Der Standard-Ausgabestrom `System.out` bietet verschiedene Methoden, um Informationen auf der Konsole auszugeben: -- Bei den print-Methoden wird die Information unverändert und linksbündig - ausgegeben -- Bei den println-Methoden wird die Information unverändert und linksbündig - ausgegeben. Zusätzlich wird ein Zeilenumbruch ausgeführt -- Bei den printf-Methoden wird die Information formatiert ausgegeben. Die - Formatierungsregeln sind nach dem Muster - _[flags]\[width][.precision]conversion-character_ aufgebaut +- `print()` — gibt den Text ohne Zeilenumbruch aus +- `println()` — gibt den Text aus und fügt einen Zeilenumbruch an +- `printf()` — gibt den Text formatiert aus; die Formatierungsregeln folgen dem + Muster `[flags][width][.precision]conversion-character` ```java title="MainClass.java" showLineNumbers public class MainClass { diff --git a/docs/documentation/data-objects.md b/docs/documentation/data-objects.md index ea4c4ef28e..80da16846b 100644 --- a/docs/documentation/data-objects.md +++ b/docs/documentation/data-objects.md @@ -5,16 +5,15 @@ sidebar_position: 40 tags: [data-objects] --- -Ein Datenobjekt ist ein Platzhalter, der zur Laufzeit eine bestimmte Stelle des -Arbeitsspeichers belegt. Die Größe des reservierten Speichers ist abhängig vom -gewählten [Datentyp](data-types)). Datenobjekte können mit Werten belegt werden, -Bezeichner ermöglichen das Ansprechen im Programmablauf. Man unterscheidet +Ein Datenobjekt ist ein Platzhalter, der zur Laufzeit eine bestimmte Stelle im +Arbeitsspeicher belegt. Die Größe des reservierten Speichers hängt vom gewählten +[Datentyp](data-types) ab. Datenobjekte können mit Werten belegt werden; +Bezeichner ermöglichen es, sie im Programmablauf anzusprechen. Man unterscheidet zwischen variablen Datenobjekten (_Variablen_) und fixen Datenobjekten -(_Konstanten_ und _Literale_). Konstanten sind fixe Datenobjekte, die über einen -Bezeichner angesprochen werden können. Sie werden mit dem Schlüsselwort `final` -deklariert. Literale sind sogenannte wörtliche Konstanten, d.h. fixe -Datenobjekte ohne Bezeichner. Da Literale über keinen Bezeichner verfügen, -können Sie im Programm nicht angesprochen werden. +(_Konstanten_ und _Literale_). Konstanten sind fixe Datenobjekte mit einem +Bezeichner und werden mit dem Schlüsselwort `final` deklariert. Literale sind +sogenannte wörtliche Konstanten — also fixe Datenobjekte ohne Bezeichner, auf +die daher im Programmcode nicht zugegriffen werden kann. ```mermaid flowchart @@ -31,10 +30,10 @@ flowchart ## Deklaration von Datenobjekten -Durch Angabe von Datentyp und Bezeichner wird ein Datenobjekt deklariert, d.h. -dem Compiler bekannt gegeben. Deklarationen werden wie jede Anweisung mit einem -Semikolon abgeschlossen. Datenobjekte gleichen Datentyps können mit Komma -getrennt aufgeführt werden. +Durch die Angabe von Datentyp und Bezeichner wird ein Datenobjekt deklariert, +d.h. dem Compiler bekannt gemacht. Deklarationen werden wie jede Anweisung mit +einem Semikolon abgeschlossen. Mehrere Datenobjekte desselben Datentyps können +kommagetrennt in einer Zeile deklariert werden. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -51,17 +50,17 @@ public class MainClass { :::info -Java ist case-sensitiv, unterscheidet also zwischen Groß- und Kleinschreibung. -Um die Lesbarkeit zu erhöhen, sollten Variablen mit einem Kleinbuchstaben -beginnen, wohingegen Konstanten immer in Großbuchstaben geschrieben werden -sollten. +Java ist case-sensitiv und unterscheidet also zwischen Groß- und +Kleinschreibung. Zur besseren Lesbarkeit sollten Variablen mit einem +Kleinbuchstaben beginnen, Konstanten hingegen vollständig in Großbuchstaben +geschrieben werden. ::: ## Initialisierung von Datenobjekten -In Java müssen Datenobjekte vor der ersten Verwendung explizit initialisiert -werden, d.h. mit einem Wert belegt werden. Der Zuweisungsoperator `=` weist dem +In Java müssen Datenobjekte vor ihrer ersten Verwendung explizit initialisiert, +d.h. mit einem Wert belegt werden. Der Zuweisungsoperator `=` weist dem Datenobjekt auf der linken Seite den Wert des Ausdrucks auf der rechten Seite zu. @@ -83,10 +82,10 @@ public class MainClass { ## Typinferenz bei Datenobjekten -Unter Typinferenz versteht man, dass bei der Deklaration eines Datenobjekts auf -die Angabe eine Datentyps verzichtet werden kann, wenn der Compiler aufgrund der -restlichen Angaben den Typ selbstständig ermitteln kann. Für die Typinferenz -wird das Schlüsselwort `var` verwendet. +Unter _Typinferenz_ versteht man, dass bei der Deklaration eines Datenobjekts +auf die explizite Angabe eines Datentyps verzichtet werden kann, wenn der +Compiler den Typ anhand der übrigen Angaben selbstständig ermitteln kann. Für +die Typinferenz wird das Schlüsselwort `var` verwendet. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -96,7 +95,7 @@ public class MainClass { i = "Text"; // Kompilierungsfehler var j = 5; - j = "Text"; // Kompilierungsfehler + j = "Text"; // Kompilierungsfehler: j ist statisch als int typisiert } } @@ -110,8 +109,9 @@ Mit `var` deklarierte Datenobjekte sind weiterhin statisch typisiert. ## Gültigkeitsbereiche von Datenobjekten -Datenobjekte sind nur innerhalb eines Anweisungsblocks gültig, d.h. man kann nur -innerhalb dieses Programmabschnitts auf das Datenobjekt zugreifen. +Datenobjekte sind nur innerhalb des Anweisungsblocks gültig, in dem sie +deklariert wurden. Außerhalb dieses Blocks kann nicht auf sie zugegriffen +werden. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -123,7 +123,7 @@ public class MainClass { public static int foo(int c) { int d; - d = a++; // Kompilierungsfehler + d = a++; // Kompilierungsfehler: a ist hier nicht sichtbar d = c++; return d; } @@ -134,9 +134,9 @@ public class MainClass { ## Typumwandlung (Type Casting) Der Cast-Operator `()` erlaubt die explizite Umwandlung eines Datentyps in einen -anderen. Bei Wertzuweisungen findet eine implizite Typumwandlung vom +anderen. Bei Wertzuweisungen findet außerdem eine implizite Typumwandlung vom niederwertigen zum höherwertigen Datentyp statt. Zu beachten ist, dass bei einer -Typumwandlung ein Genauigkeitsverlust stattfinden kann. +Typumwandlung ein Genauigkeitsverlust auftreten kann. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -146,11 +146,11 @@ public class MainClass { int b = 3; double result; - // implizite Typumwandlung + // implizite Typumwandlung: Ergebnis ist 4.0, da beide Operanden int sind result = a / b; System.out.println(result); - // explizite Typumwandlung + // explizite Typumwandlung: Ergebnis ist 4.666... result = (double) a / b; System.out.println(result); } @@ -158,8 +158,7 @@ public class MainClass { } ``` -Die Wertigkeit von Datentypen entscheidet darüber, welche Typumwandlungen -möglich sind. +Die Wertigkeit der Datentypen bestimmt, welche Typumwandlungen möglich sind. ```mermaid flowchart diff --git a/docs/documentation/data-types.mdx b/docs/documentation/data-types.mdx index ff6dec878d..d586b008d4 100644 --- a/docs/documentation/data-types.mdx +++ b/docs/documentation/data-types.mdx @@ -8,16 +8,15 @@ tags: [data-types] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Datentypen legen neben der Größe des Arbeitsspeichers, die ein Datenobjekt -benötigt, auch die Art der Information fest, die im Datenobjekt gespeichert -werden kann. +Datentypen legen fest, welche Art von Information in einem Datenobjekt +gespeichert werden kann und wie viel Arbeitsspeicher dafür reserviert wird. Primitive Datentypen sind fest in der Programmiersprache verankert und können -durch entsprechende Schlüsselwörter angesprochen werden. Java kennt 8 solcher -primitiver Datentypen. +über entsprechende Schlüsselwörter verwendet werden. Java kennt 8 primitive +Datentypen. | Datentyp | Größe | Wertebereich | | -------- | ------ | --------------------------------------------------------- | @@ -58,12 +57,12 @@ Weitere Informationen zu strukturierten Datentypen finden sich im Kapitel Klassen, die über einen oder mehrere formale Typparameter verfügen, werden als generische Klassen bezeichnet. Generische Klassen können mit verschiedenen -Datentypen verwendet werden und ermöglichen dadurch die Wiederverwendung von -Code unter Beibehaltung statischer Typsicherheit. Unter Typsicherheit versteht -man, dass Datentypen gemäß ihrer Definition verwendet werden und dabei keine -Typverletzungen auftreten. Bei statisch typisierten Sprachen findet die -Typprüfung bei der Kompilierung statt. Beispiele für generische Klassen sind die -Klasse `ArrayList` sowie die Klasse `HashMap`. +Datentypen verwendet werden und ermöglichen so die Wiederverwendung von Code bei +gleichzeitiger statischer Typsicherheit. Unter _Typsicherheit_ versteht man, +dass Datentypen gemäß ihrer Definition verwendet werden und keine +Typverletzungen auftreten. Bei statisch typisierten Sprachen erfolgt die +Typprüfung bereits zur Kompilierzeit. Beispiele für generische Klassen sind +`ArrayList` und `HashMap`. :::info @@ -75,12 +74,11 @@ Weitere Informationen zu generischen Datentypen finden sich im Kapitel -Abstrakte Datentypen sind Sammlungen von Daten samt den dazugehörigen -Operationen wie Einfügen, Löschen etc. Beispiele für abstrakte Datentypen sind -Listen (z.B. die Klassen `ArrayList` und `LinkedList`), Mengen (z.B. die -Klassen `HashSet` und `TreeSet`), Warteschlangen (z.B. die Klassen -`LinkedList` und `PriorityQueue`) sowie Assoziativspeicher (z.B. die -Klassen `HashMap` und `TreeMap`). +Abstrakte Datentypen sind Sammlungen von Daten zusammen mit den dazugehörigen +Operationen wie Einfügen oder Löschen. Beispiele für abstrakte Datentypen sind +Listen (z.B. `ArrayList` und `LinkedList`), Mengen (z.B. `HashSet` und +`TreeSet`), Warteschlangen (z.B. `LinkedList` und `PriorityQueue`) +sowie Assoziativspeicher (z.B. `HashMap` und `TreeMap`). :::info diff --git a/docs/documentation/dates-and-times.md b/docs/documentation/dates-and-times.md index b57aaa96f2..6837bd8dc3 100644 --- a/docs/documentation/dates-and-times.md +++ b/docs/documentation/dates-and-times.md @@ -5,8 +5,9 @@ sidebar_position: 142 tags: [java-api, dates-and-times] --- -Die Klasse `LocalDateTime` liefert alle relevanten Informationen zum fast -weltweit verwendeten Kalendersystem ISO-8601 (gregorianischer Kalender). +Die Klasse `LocalDateTime` stellt Informationen zum gregorianischen Kalender +(ISO-8601) bereit und gibt Zugriff auf Jahr, Monat, Tag, Stunde, Minute und +Sekunde der aktuellen Systemzeit. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -22,9 +23,9 @@ public class MainClass { } ``` -Neben den print-Methoden des Standard-Ausgabestroms `System.out` besitzt die -Klasse `System` auch die Methode `long currentTimeMillis()`, die die Differenz -in Millisekunden zwischen der aktuellen Systemzeit und dem Nullpunkt zurückgibt. +Neben `LocalDateTime` bietet die Klasse `System` die Methode +`long currentTimeMillis()`, die die Differenz in Millisekunden zwischen der +aktuellen Systemzeit und dem Nullpunkt (1. Januar 1970, 0 Uhr) zurückgibt. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -39,6 +40,6 @@ public class MainClass { :::info -Der festgelegte Nullpunkt ist der 1. Januar 1970, 0 Uhr. +Der Nullpunkt (Unix-Epoch) ist der 1. Januar 1970 um 0:00 Uhr UTC. ::: diff --git a/docs/documentation/enumerations.md b/docs/documentation/enumerations.md index 28e9b031ed..49bf9d83ab 100644 --- a/docs/documentation/enumerations.md +++ b/docs/documentation/enumerations.md @@ -5,16 +5,15 @@ sidebar_position: 150 tags: [enumerations] --- -Bei einer Aufzählung (Enumeration) handelt es sich um eine spezielle Klasse, von -der nur eine vorgegebene, endliche Anzahl an Instanzen existiert. Diese -Instanzen werden als _Aufzählungskonstanten_ bezeichnet. Technisch gesehen -handelt es sich bei Aufzählungskonstanten um öffentliche, statische Konstanten -vom Typ der Aufzählung. +Eine Aufzählung (Enumeration) ist eine spezielle Klasse, von der nur eine +vorgegebene, endliche Anzahl an Instanzen existiert. Diese Instanzen heißen +_Aufzählungskonstanten_ und sind technisch gesehen öffentliche, statische +Konstanten vom Typ der Aufzählung selbst. ## Implementieren von Aufzählungen -Die Definition einer Aufzählung erfolgt analog zur Definition von Klassen, das -Schlüsselwort hierfür lautet `enum`. +Eine Aufzählung wird ähnlich wie eine Klasse definiert. Das Schlüsselwort lautet +`enum`. ```java title="WeekDay.java" showLineNumbers public enum Weekday { @@ -48,14 +47,12 @@ public enum Weekday { ## Verwenden von Aufzählungen -Aufzählungen besitzen eine Reihe hilfreicher Methoden: +Aufzählungen stellen eine Reihe hilfreicher Methoden bereit: -- Die statische Methode `T[] values()` gibt alle Aufzählunskonstanten als Feld - zurück -- Die statische Methode `T valueOf(name: String)` gibt zu einer eingehenden - Zeichenkette die dazugehörige Aufzählungskonstante zurück -- Die Methode `int ordinal()` gibt die Ordnungszahl der Aufzählungskonstanten - zurück +- `T[] values()` — statisch; gibt alle Aufzählungskonstanten als Feld zurück +- `T valueOf(name: String)` — statisch; gibt die Aufzählungskonstante zur + angegebenen Zeichenkette zurück +- `int ordinal()` — gibt die nullbasierte Ordnungszahl der Konstante zurück ```java title="MainClass.java" showLineNumbers public class MainClass { diff --git a/docs/documentation/exceptions.mdx b/docs/documentation/exceptions.mdx index 284f3c4216..8db8f535f1 100644 --- a/docs/documentation/exceptions.mdx +++ b/docs/documentation/exceptions.mdx @@ -9,56 +9,45 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; Programmfehler (Bugs) führen dazu, dass Programme unerwartete Ergebnisse liefern -oder abstürzen. Je komplexer das Programm, desto wichtiger wird eine durchdachte -und konsequente Fehlerbehandlung. Man unterscheidt dabei zwischen verschiedenen -Fehlerarten: Kompilierungsfehler, Logikfehler und Laufzeitfehler. +oder abstürzen. Je komplexer das Programm, desto wichtiger ist eine +strukturierte Fehlerbehandlung. Es gibt drei grundlegende Fehlerarten: +Kompilierungsfehler, Logikfehler und Laufzeitfehler. -Kompilierungsfehler sind Programmfehler, die verhindern, dass das Programm -ausgeführt werden kann. Sie können relativ einfach behoben werden, da sie schon -zur Designzeit auftreten und von den meisten Entwicklungsumgebungen direkt -angezeigt werden. +Kompilierungsfehler verhindern, dass das Programm übersetzt und ausgeführt +werden kann. Da sie bereits beim Schreiben des Codes auftreten und von +Entwicklungsumgebungen direkt angezeigt werden, lassen sie sich in der Regel +leicht beheben. Verhält sich das Programm nicht wie beabsichtigt, spricht man von Logikfehlern. -Sie sind mit am schwersten zu entdecken und zu beheben. Zur Unterstüzung bei der -Fehlersuche und -behandlung kann unter Anderem der Debugger verwendet werden. -Der Debugger ermöglicht es, Programme zur Laufzeit zu analysieren und zu -steuern. Durch das Setzen von Haltepunkten (Breakpoints) kann die Ausführung des -Programms an beliebiger Stelle angehalten werden. Dadurch lassen sich z.B. die -Inhalte von Datenobjekten überprüfen. Zudem bietet der Debugger die Möglichkeit, -die weitere Ausführung des Programms in der gewünschten Schrittweite -forzuführen. +Sie sind schwer zu entdecken, da das Programm ausgeführt wird, aber falsche +Ergebnisse liefert. Der Debugger kann dabei helfen: Er ermöglicht die +schrittweise Ausführung und das Überprüfen von Variablenwerten zur Laufzeit. -Laufzeitfehler treten erst beim Ausführen des Programms auf. Sie entstehen meist -dann, wenn das Programm versucht, eine Operation auszuführen, die nicht -ausgeführt werden kann (z.B. die Division durch Null). Diese Situationen werden -auch als Ausnahmen (Exceptions) bezeichnet. Ausnahmen gewährleisten eine klare -Trennung zwischen funktionalem Code und Code zur Fehlerbehandlung. Die -Fehlerbehandlung erfolgt dabei gemäß dem Ausnahmenbehandlungsprozess: nachdem -eine Ausnahme ausgelöst wurde, kann bzw. muss diese je nach Ausnahmenart vom -Empfänger der Ausnahme entweder behandelt oder weitergeleitet werden -_Catch-or-Throw-Regel_ Man unterscheidet zwischen _geprüften_ (checked) und -_ungeprüften_ (unchecked) Ausnahmen. Geprüfte Ausnahmen müssen, ungeprüfte -Ausnahmen können behandelt bzw. weitergeleitet werden. +Laufzeitfehler treten erst beim Ausführen des Programms auf, wenn das Programm +eine Operation versucht, die nicht möglich ist (z.B. Division durch null oder +Zugriff auf ein null-Objekt). Solche Situationen werden als Ausnahmen +(Exceptions) bezeichnet. Die Fehlerbehandlung folgt der _Catch-or-Throw-Regel_: +Eine Ausnahme muss entweder abgefangen (catch) oder weitergeleitet (throw) +werden. Geprüfte (checked) Ausnahmen müssen behandelt werden; ungeprüfte +(unchecked) Ausnahmen können es. ## Die Klassenhierarchie der Laufzeitfehler -Die Klasse `Throwable` stellt die Oberklasse aller Laufzeitfehler dar. -Schwerwiegende Fehler (hauptsächlich Probleme in der JVM (Java Virtual Machine)) -werden durch Unterklassen der Klasse `Error` abgebildet, geprüfte Ausnahmen -durch Unterklassen der Klasse `Exception` und ungeprüfte Ausnahmen durch -Unterklassen der Klasse `RuntimeException`. +`Throwable` ist die Oberklasse aller Laufzeitfehler. Schwerwiegende JVM-Fehler +sind Unterklassen von `Error`. Geprüfte Ausnahmen sind Unterklassen von +`Exception`, ungeprüfte Ausnahmen Unterklassen von `RuntimeException`. ```mermaid classDiagram @@ -72,10 +61,9 @@ classDiagram ## Definition von Ausnahmenklassen -Eigene Ausnahmenklassen werden durch einfaches Ableiten von einer bestehenden -Ausnahmenklasse definiert. Ausnahmenklassen sollten dabei immer von der Klasse -`Exception` oder einer ihrer Unterklassen abgeleitet werden, nicht von der -Klasse `Error`. +Eigene Ausnahmenklassen werden durch Ableitung von einer bestehenden +Ausnahmenklasse definiert. Es sollte immer von `Exception` oder einer ihrer +Unterklassen abgeleitet werden — nicht von `Error`. ```java title="InvalidValueException.java" showLineNumbers public class InvalidValueException extends Exception { @@ -89,9 +77,9 @@ public class InvalidValueException extends Exception { ## Auslösen von Ausnahmen -Mit dem Schlüsselwort `throw` kann innerhalb einer Methode eine Ausnahme -ausgelöst werden. Die Methode, in der die Ausnahme ausgelöst wird, muss mit dem -Schlüsselwort `throws` die Ausnahmenklasse angeben, die ausgelöst werden kann. +Mit dem Schlüsselwort `throw` wird eine Ausnahme ausgelöst. Die auslösende +Methode muss mit `throws` deklarieren, welche geprüften Ausnahmen sie werfen +kann. ```java title="Computer.java (Auszug)" showLineNumbers public abstract class Computer { @@ -110,10 +98,9 @@ public abstract class Computer { ## Weiterleiten von Ausnahmen -Ausnahmen können weitergeleitet werden. Hierbei wird die Fehlerbehandlung an die -nächsthöhere Ebene weitergegeben. Um eine Ausnahme weiterzuleiten, muss in der -weiterleitenden Methode mit `throws` die Ausnahme angegeben werden, die -ausgelöst werden kann. +Ausnahmen können an den Aufrufer weitergeleitet werden, anstatt sie direkt zu +behandeln. Die weiterleitende Methode deklariert dafür ebenfalls `throws` mit +der entsprechenden Ausnahmenklasse. ```java title="Notebook.java (Auszug)" showLineNumbers public final class Notebook extends Computer implements Comparable { @@ -129,11 +116,9 @@ public final class Notebook extends Computer implements Comparable { ## Abfangen von Ausnahmen -Mit Hilfe der try-catch-Anweisung können Methoden, die eine Ausnahme auslösen -können, überwacht werden; d.h. die Ausnahmen werden gegebenenfalls abgefangen. -Der try-Block enthält die Anweisungen, die überwacht werden sollen, der -catch-Block enthält die eigentliche Fehlerbehandlung. Als Parameter von `catch` -muss angegeben werden, welche Ausnahme(n) abgefangen werden soll(en). +Die `try-catch`-Anweisung überwacht einen Codeblock auf Ausnahmen. Der +`try`-Block enthält den zu überwachenden Code, der `catch`-Block die +Fehlerbehandlung für eine bestimmte Ausnahmenklasse. ```java title="MainClass.java" showLineNumbers public class MainClass { diff --git a/docs/documentation/files.md b/docs/documentation/files.md index d02c02323c..c1658ef098 100644 --- a/docs/documentation/files.md +++ b/docs/documentation/files.md @@ -5,18 +5,15 @@ sidebar_position: 143 tags: [java-api, files] --- -Die Klasse `File` ermöglicht die Arbeit mit Dateien und Verzeichnissen. Mit -Hilfe der Methode `boolean exists()` kann beispielsweise geprüft werden, ob ein -entsprechendes Verzeichnis bzw. eine entsprechende Datei existiert oder nicht. -Die Klasse bietet zudem M ethoden zum Erstellen und Löschen von Verzeichnissen -bzw. Dateien. Zum Erzeugen eines File-Objekts wird entweder ein Pfad zu einem -Verzeichnis bzw. zu einer Datei oder ein _URI_ (Unified Resource Identifier) -benötigt. +Die Klasse `File` ermöglicht die Arbeit mit Dateien und Verzeichnissen im +Dateisystem. Sie bietet Methoden zum Prüfen, Erstellen und Löschen von Dateien +und Verzeichnissen. Zum Erstellen eines `File`-Objekts wird ein Pfad oder ein +_URI_ (Uniform Resource Identifier) angegeben. -## Lesen von Dateien mit Hilfe der Klasse _Scanner_ +## Lesen von Dateien mit der Klasse _Scanner_ -Zum Lesen einer Datei können entweder [Datenstromklassen](io-streams) oder die -Klasse `Scanner` verwendet werden. +Zum zeilenweisen Lesen einer Datei kann neben den +[Datenstromklassen](io-streams) auch die Klasse `Scanner` verwendet werden. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -45,10 +42,10 @@ Nach der letzten Verwendung sollte die Methode `void close()` der Klasse ## Absolute und relative Pfadangaben -Beim Zugriff auf Verzeichnisse bzw. Dateien unterscheidet man zwischen absoluten -und relativen Pfadangaben. Bei absoluten Pfadangaben wird der vollständige Pfad -von der Wurzel des jeweiligen Verzeichnissystems bis zum Ziel angegeben, bei -relativen der Weg von einem festgelegten Bezugspunkt bis zum Ziel. +Bei Pfadangaben unterscheidet man zwischen absoluten und relativen Pfaden. Ein +absoluter Pfad beschreibt den vollständigen Weg vom Wurzelverzeichnis bis zur +Zieldatei. Ein relativer Pfad gibt den Weg ausgehend von einem festgelegten +Bezugspunkt an. :::info @@ -67,8 +64,8 @@ flowchart LR documents[documents] --> documentB[DocumentB.txt]@{ shape: doc} ``` -Die Datei `DocumentA.txt` kann entweder über den absoluten Pfad -`C:\Temp\DocumentA.txt` oder über den relativen Pfad `documents/DocumentA.txt` -(Bezugspunkt ist das Verzeichnis `Project`); die Datei `DocumentB.txt` über den -absoluten Pfad `C:\workspace\Project\documents\documentB.txt` oder über den -relativen Pfad `../../Temp/documentA.txt` angesprochen werden. +Die Datei `DocumentA.txt` kann über den absoluten Pfad `C:\Temp\DocumentA.txt` +oder den relativen Pfad `../../Temp/DocumentA.txt` (Bezugspunkt: `Project`) +angesprochen werden. Die Datei `DocumentB.txt` über den absoluten Pfad +`C:\workspace\Project\documents\DocumentB.txt` oder den relativen Pfad +`documents/DocumentB.txt`. diff --git a/docs/documentation/generics.md b/docs/documentation/generics.md index ae20c7c995..5a6fbab8e4 100644 --- a/docs/documentation/generics.md +++ b/docs/documentation/generics.md @@ -5,20 +5,17 @@ sidebar_position: 270 tags: [generics] --- -Quellcode sollte generell so allgemein bzw. generisch geschrieben werden, dass -er für unterschiedliche Datenstrukturen und Datentypen verwendet werden kann. -Das Ziel der generischen Programmierung ist die Entwicklung von -wiederverwendbarem Code. In Java verwendet man das Konzept der generischen -Datentypen, also Klassen, die mit verschiedene Datentypen verwendet werden -können. +Quellcode sollte so allgemein wie möglich geschrieben werden, damit er für +unterschiedliche Datentypen und Datenstrukturen wiederverwendet werden kann. In +Java wird dieses Ziel mit _generischen Datentypen_ erreicht — also Klassen, die +mit verschiedenen Typen parametrisiert werden können. ## Generische Klassen ohne Java Generics -Auch ohne Java Generics kann in Java mit Hilfe der Klasse `Object` generisch -programmiert werden. Der Nachteil besteht darin, dass durch den Upcast einer -beliebigen Klasse auf die Klasse `Object` die spezifischen Methoden der Klasse -nicht mehr verwendet werden können und der dadurch notwendige Downcast zu -Laufzeitfehlern führen kann. +Auch ohne Java Generics lässt sich in Java mit der Klasse `Object` generisch +programmieren. Der Nachteil: Durch den Upcast auf `Object` gehen die +spezifischen Methoden der Originalklasse verloren, und der notwendige Downcast +beim Auslesen kann zu Laufzeitfehlern führen. Die Klasse `Box` ermöglicht das Speichern einer beliebig typisierten Information. @@ -49,7 +46,7 @@ public class MainClass { public static void main(String[] args) { Box box = new Box(); box.set(5); - String i = (String) box.get(); // Laufzeitfehler + String i = (String) box.get(); // Laufzeitfehler: int ist kein String System.out.println(i); } @@ -58,12 +55,11 @@ public class MainClass { ## Generische Klassen mit Java Generics -Klassen und Methoden können in Java mit Typen parametrisiert werden. Diese -werden durch spitze Klammern `<>` gekennzeichnet und stellen Platzhalter für -konkrete Datentypen dar. Beim Kompilieren werden alle generischen Informationen -vollständig entfernt und durch die konkreten Datentypen ersetzt. Durch die -dadurch vorhandene statische Typsicherheit können Laufzeitfehler verhindert und -Fehler bereits beim Kompilieren entdeckt werden. +Klassen und Methoden können in Java mit Typparametern versehen werden. Diese +werden in spitzen Klammern `<>` notiert und stellen Platzhalter für konkrete +Datentypen dar. Beim Kompilieren ersetzt der Compiler alle generischen +Informationen durch die konkreten Typen. Dadurch entsteht statische +Typsicherheit, die viele Fehler bereits zur Kompilierzeit aufdeckt. Die generische Klasse `Box` ermöglicht das Speichern einer beliebig typisierten Information mit Hilfe des Typparameters `T`. @@ -95,7 +91,7 @@ public class MainClass { public static void main(String[] args) { Box box = new Box<>(); box.set(5); - String i = box.get(); // Kompilierungsfehler + String i = box.get(); // Kompilierungsfehler: Integer ist kein String System.out.println(i); } @@ -146,8 +142,8 @@ public class MainClass { ## Namensrichtlinien für Typparameter -Um den Einsatzbereich von Typparametern in generischen Klassen und Methoden -kenntlich zu machen, sollte man festgelegte Zeichen verwenden. +Um den Einsatzbereich von Typparametern in generischen Klassen und Methoden zu +kennzeichnen, sollten die folgenden etablierten Kürzel verwendet werden. | Typparameter | Einsatzbereich | | ------------- | ----------------------------------------- | @@ -158,10 +154,10 @@ kenntlich zu machen, sollte man festgelegte Zeichen verwenden. ## Varianz -Bei der Deklaration einer generischen Klasse ermöglicht der Wildcard-Typ `?` die -Angabe eines unbestimmten Typs. Dieser kann gar nicht (**Bivarianz**), nach oben -(**Kovarianz**), nach unten (**Kontravarianz**), oder sowohl nach oben als auch -nach unten (**Invarianz**) eingeschränkt werden. +Mit dem Wildcard-Typ `?` kann bei der Deklaration einer generischen Klasse ein +unbestimmter Typ angegeben werden. Dieser kann gar nicht (_Bivarianz_), nach +oben (_Kovarianz_), nach unten (_Kontravarianz_) oder in beide Richtungen +(_Invarianz_) eingeschränkt werden. Die generische Klasse `Box` ermöglicht das Speichern einer beliebig typisierten Information. @@ -182,10 +178,9 @@ public class Box { } ``` -In der main-methode der Startklasse werden verschiedene Boxen unterschiedlich -deklariert und anschließend initialisiert. Dabei ist die Klasse `String` eine -Unterklasse der Klasse `Object`, die Klasse `Integer` eine Unterklasse der -Klasse `Number` und diese eine Unterklasse der Klasse `Object`. +In der main-Methode der Startklasse werden verschiedene Boxen unterschiedlich +deklariert und initialisiert. Dabei gilt: `String` und `Integer` sind +Unterklassen von `Object`, `Integer` ist außerdem eine Unterklasse von `Number`. ```java title="MainClass.java" showLineNumbers public class MainClass { diff --git a/docs/documentation/gui.md b/docs/documentation/gui.md index 7775567fc1..27f9d0be3d 100644 --- a/docs/documentation/gui.md +++ b/docs/documentation/gui.md @@ -5,26 +5,22 @@ sidebar_position: 360 tags: [gui] --- -Eine grafische Benutzeroberfläche oder auch _GUI_ (Graphical User Interface) hat -die Aufgabe, Programme mittels grafischer Bildschirmelemente bedienbar zu -machen. So ermöglichen _Controls_ wie Eingabefelder, Drucktasten und -Ausgabefelder die Interaktion mit der Anwendung und _Container_ die -strukturierte Darstellung und Verwaltung anderer Bildschirmelemente. _Dialoge_ -wie Nachrichtendialoge und Dateiauswahl-Dialoge widerum stellen vordefinierte -Oberflächen dar, mit deren Hilfe wiederkehrende Anwendungsfälle abgedeckt werden -können. +Eine grafische Benutzeroberfläche (_GUI_, Graphical User Interface) macht +Programme durch grafische Bildschirmelemente bedienbar. _Controls_ wie +Eingabefelder, Schaltflächen und Beschriftungen ermöglichen die Interaktion. +_Container_ ordnen und verwalten andere Bildschirmelemente. _Dialoge_ wie +Meldungsfenster und Dateiauswahl-Dialoge decken wiederkehrende Anwendungsfälle +ab. ## Aufbau grafischer Benutzeroberflächen -Da es sich bei grafischen Benutzeroberflächen um komplexe Anwendungen handelt, -werden diese in der Regel in verschiedene Bereiche wie Aufbau, Aussehen und -Verhalten aufgeteilt (_Separation of Concerns_). Als Beispiel sei hier der -Aufbau einer klassischen Webseite aufgeführt: HTML bestimmt den Aufbau, CSS das -Aussehen und JavaScript das Verhalten der Webseite. +Da grafische Benutzeroberflächen komplex sind, werden sie nach dem Prinzip der +_Separation of Concerns_ in Bereiche wie Aufbau, Aussehen und Verhalten +aufgeteilt. Ein bekanntes Beispiel ist eine klassische Webseite: HTML definiert +den Aufbau, CSS das Aussehen und JavaScript das Verhalten. -Das Entwurfmuster MVC (_Model-View-Controller_) stellt einen gängigen Ansatz zur -Entwicklung von grafischen Benutzeroberflächen dar, bei dem die grafische -Benutzeroberfläche in drei Bereiche unterteilt wird: +Das Entwurfsmuster MVC (_Model-View-Controller_) ist ein gängiger Ansatz für +GUI-Entwicklung und teilt die Oberfläche in drei Bereiche auf: - Das _Model_ ist für die Datenhaltung und -verwaltung zuständig - Die _View_ ist für die Darstellung der Oberfläche zuständig, welche wiederum @@ -49,13 +45,10 @@ MVP (_Model-View-Presenter_) oder MVVM (_Model-View-ViewModel_) verwendet. ## Ereignisse (Events) -Ereignisse (Events) sind Nachrichten, die über das System weitergeleitet werden. -Auf grafischen Benutzeroberflächen werden Ereignisse z.B. durch das Betätigen -einer Drucktaste ausgelöst. Weitere typische Ergeignisse sind das Betätigen -einer Maustaste, Tastatureingaben oder das Vergrößern bzw. Verkleinern eines -Fensters. - -Die Behandlung dieser Ereignisse wird durch das Delegationsmodell festgelegt: +Ereignisse (Events) sind Nachrichten, die durch Benutzerinteraktionen ausgelöst +werden — z.B. durch das Klicken einer Schaltfläche, eine Tastatureingabe oder +das Vergrößern eines Fensters. Das Delegationsmodell legt fest, wie Ereignisse +behandelt werden: 1. Empfänger können sich beim Sender für ein Ereignis registrieren 2. Der Sender löst das Ereignis aus und übergibt das erzeugte Ereignis-Objekt an diff --git a/docs/documentation/hashing.mdx b/docs/documentation/hashing.mdx index 9c654af540..37fa66276b 100644 --- a/docs/documentation/hashing.mdx +++ b/docs/documentation/hashing.mdx @@ -8,11 +8,9 @@ tags: [hashing] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Unter Schlüsseltransformationen (Hashing) versteht man die Transformation einer -großen Datenmenge in eine kleinere. Die größere Datenmenge wird dabei als -Schlüssel, die kleinere als Hashcode bezeichnet. Die Transformation erfolgt über -eine sogenannte Hashfunktion (auch Streuwertfunktion). Wichtig dabei ist, dass -der Hashcode nur vom Zustand des Schlüssels abhängen darf. +Schlüsseltransformation (Hashing) bezeichnet die Abbildung einer großen +Datenmenge (Schlüssel) auf eine kleinere Datenmenge (Hashcode) mittels einer +Hashfunktion. Der Hashcode darf dabei nur vom Zustand des Schlüssels abhängen. ```mermaid flowchart @@ -24,11 +22,10 @@ flowchart ## Hashtabellen -Hashtabellen sind spezielle Datenstrukturen, die für den schnellen Zugriff -konzipiert wurden. Mit Hilfe einer Hashfunktion wird der Index berechnet, an der -ein Schlüssel gespeichert wird. Bei Hashtabellen soll durch das Hashing eine -gleichmäßige Streuung der Einträge in der Tabelle erreicht werden. Aus diesem -Grund werden Hashtabellen auch als Streuwerttabellen bezeichnet. +Hashtabellen sind Datenstrukturen für schnellen Zugriff. Der Index eines +Eintrags wird über eine Hashfunktion berechnet, sodass Einträge gleichmäßig in +der Tabelle gestreut sind. Daher werden Hashtabellen auch Streuwerttabellen +genannt. | Index | Schlüssel | Hashcode | | ----- | --------- | -------- | @@ -40,11 +37,15 @@ Grund werden Hashtabellen auch als Streuwerttabellen bezeichnet. ## Hashfunktionen +Eine Hashfunktion berechnet aus einem Schlüssel (Hashcode) einen Tabellenindex. +Die beiden gebräuchlichsten Verfahren sind die Divisionsrestmethode und die +multiplikative Methode. + -Die Divisionsrest-Methode stellt eine einfache und schnelle Hashfunktion dar. -Die Berechnung des Index erfolgt dabei gemäß der Formel `ℎ(𝑘) = 𝑘 𝑚𝑜𝑑 𝑚`. +Die Divisionsrestmethode ist eine einfache und schnelle Hashfunktion. Der Index +wird nach der Formel `ℎ(𝑘) = 𝑘 𝑚𝑜𝑑 𝑚` berechnet. | Schlüssel | Hashcode | Index | | --------- | -------- | ------------- | @@ -62,9 +63,8 @@ Die Berechnung des Index erfolgt dabei gemäß der Formel `ℎ(𝑘) = 𝑘 𝑚 -Die Multiplikative Methode stellt eine Hashfunktion dar, die man als -Verallgemeinerung der Divisionsrest-Methode sehen kann. Die Berechnung des Index -erfolgt dabei gemäß der Formel `ℎ(𝑘) = ⌊𝑚 ∗ (𝑘 ∗ 𝐴 𝑚𝑜𝑑 1)⌋`. +Die multiplikative Methode ist eine Verallgemeinerung der Divisionsrestmethode. +Der Index wird nach der Formel `ℎ(𝑘) = ⌊𝑚 ∗ (𝑘 ∗ 𝐴 𝑚𝑜𝑑 1)⌋` berechnet. | Schlüssel | Hashcode | Index | | --------- | -------- | ---------------------------- | @@ -91,20 +91,19 @@ Als Wert für die Konstante 𝐴 wird gerne der Goldene Schnitt (~0,62) verwende ## Kollisionen -Werden zu unterschiedlichen Schlüsseln dieselben Indizes ermittelt, entstehen -dadurch sogenannte Kollisionen. Um Kollisionen bestmöglichen zu vermeiden, muss -eine geeignete Tabellengröße sowie eine geeignete Hashfunktion gewählt werden. -Zur Auflösung von Kollisionen gibt es verschiedene Möglichkeiten. +Ergibt die Hashfunktion für zwei unterschiedliche Schlüssel denselben Index, +spricht man von einer Kollision. Um Kollisionen zu minimieren, müssen +Tabellengröße und Hashfunktion sorgfältig gewählt werden. Für unvermeidliche +Kollisionen gibt es zwei grundlegende Auflösungsstrategien. -Beim geschlossenen Hashing mit offener Adressierung wird bei einer Kollision -über unterschiedliche Verfahren eine freie Stelle in der Hashtabelle gesucht: -Beim linearen Sondieren wird mit festen Intervallschritten nach einer freien -Stelle gesucht, beim quadratischen Sondieren wird der Intervallschritt nach -jedem erfolglosen Versuch quadriert und beim doppelten Hashing wird der -Intervallschritt mit Hilfe einer zusätzlichen Hashfunktion berechnet. +Beim geschlossenen Hashing wird bei einer Kollision eine freie Stelle in der +Hashtabelle gesucht. Beim linearen Sondieren geschieht dies mit festen +Intervallschritten, beim quadratischen Sondieren wächst der Schritt quadratisch, +und beim doppelten Hashing wird der Schritt über eine zweite Hashfunktion +berechnet. | Index | Schlüssel | | ----- | --------- | @@ -117,11 +116,9 @@ Intervallschritt mit Hilfe einer zusätzlichen Hashfunktion berechnet. -Beim offenen Hashing mit geschlossener Adressierung werden alle Schlüssel mit -demselben Index in einem Behälter (Bucket) gespeichert. Diese Behälter werden -oft mit Hilfe linearer Listen realisiert. Bei der Suche nach einem Schlüssel -muss also zunächst der richtige Behälter ermittelt und anschließend der Behälter -durchsucht werden. +Beim offenen Hashing werden alle Schlüssel mit demselben Index in einem Behälter +(Bucket) gespeichert, der in der Regel als verkettete Liste realisiert wird. Bei +einer Suche wird zuerst der Bucket bestimmt, dann der Bucket durchsucht. | Index | Schlüssel | | ----- | ------------- | diff --git a/docs/documentation/inheritance.mdx b/docs/documentation/inheritance.mdx index 0cb622f3d9..9d0859d184 100644 --- a/docs/documentation/inheritance.mdx +++ b/docs/documentation/inheritance.mdx @@ -9,22 +9,19 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; Bei der Modellierung von Klassen stellt man häufig fest, dass sich einige -Klassen der Struktur und dem Verhalten nach ähneln. In solchen Fällen hat man -die Möglichkeit, die gemeinsamen Strukturen und Verhaltensweisen aus den -speziellen Klassen zu extrahieren und in einer allgemeineren Klasse -unterzubringen. Dies wird als _Generalisierung_ bezeichnet. Umgekehrt gibt es -oftmals auch Bedarf, eine bestehende Klasse um zusätzliche Attribute und/oder -Methoden zu erweitern. Dies bezeichnet man als _Spezialisierung_ Die Beziehung -zwischen einer speziellen Klasse und einer allgemeinen Klasse wird _Vererbung_ -bezeichnet. Die speziellen Klasse einer Vererbung werden als _Unterklassen_ (Sub -Classes), die allgemeinen Klassen als _Oberklassen_ (Super Classes) bezeichnet. +Klassen in Struktur und Verhalten ähneln. In solchen Fällen können die +gemeinsamen Teile in einer allgemeineren Klasse zusammengefasst werden +(_Generalisierung_). Umgekehrt lässt sich eine bestehende Klasse um zusätzliche +Attribute und Methoden erweitern (_Spezialisierung_). Die Beziehung zwischen +einer speziellen und einer allgemeinen Klasse nennt man _Vererbung_. Die +spezielle Klasse heißt _Unterklasse_ (Sub Class), die allgemeine _Oberklasse_ +(Super Class). ## Implementieren von Vererbung -Die Vererbung wird mit dem Schlüsselwort `extends` realisiert. In der Oberklasse -können Attribute und Methoden mit dem Schlüsselwort `protected` als geschützt -festlegt werden. Unterklassen können auf alle öffentlichen und geschützten -Attribute und Methoden der Oberklasse zugreifen. +Vererbung wird mit dem Schlüsselwort `extends` realisiert. Attribute und +Methoden der Oberklasse können mit `protected` als geschützt markiert werden, +sodass Unterklassen darauf zugreifen können. @@ -69,18 +66,17 @@ public class Notebook extends Computer { :::info -In den Konstruktoren der Unterklasse muss ein Konstruktor der Oberklasse mit -Hilfe von `super` aufgerufen werden. +Im Konstruktor einer Unterklasse muss mit `super(...)` ein Konstruktor der +Oberklasse aufgerufen werden. ::: ## Überschreiben von Methoden -Wird in einer Unterklasse eine Methode definiert, die der Signatur einer Methode -der Oberklasse entspricht, wird die Methode der Oberklasse _überschrieben_, d.h. -von der Unterklasse neu implementiert. Bei Bedarf kann die ursprüngliche -Methodenimplementierung der Oberklasse mit Hilfe der Objektreferenz `super` -aufgerufen werden. +Definiert eine Unterklasse eine Methode mit derselben Signatur wie die +Oberklasse, _überschreibt_ sie diese Methode und ersetzt damit ihre +Implementierung. Die ursprüngliche Implementierung der Oberklasse kann bei +Bedarf über `super` aufgerufen werden. diff --git a/docs/documentation/inner-classes.mdx b/docs/documentation/inner-classes.mdx index 1b6200994c..ab728adc7d 100644 --- a/docs/documentation/inner-classes.mdx +++ b/docs/documentation/inner-classes.mdx @@ -8,19 +8,18 @@ tags: [inner-classes] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Java bietet die Möglichkeit, Klassen und Schnittstellen zu verschachteln. Das -Ziel von inneren Klassen ist eine Definition von Hilfsklassen möglichst nahe an -der Stelle, wo sie gebraucht werden. Beispiele für Hilfsklassen sind -Ausnahmeklassen, Komparatoren und Ereignisbehandler. Alle bisherigen Klassen -werden auch als _äußerer Klassen_ bzw. _Top-Level-Klassen_ bezeichnet. +Java erlaubt es, Klassen und Schnittstellen zu verschachteln. Ziel innerer +Klassen ist es, Hilfsklassen möglichst nah an der Stelle zu definieren, wo sie +benötigt werden — z.B. Ausnahmeklassen, Komparatoren oder Ereignisbehandler. +Alle bisher bekannten Klassen, die auf der obersten Ebene definiert sind, nennt +man auch _äußere Klassen_ oder _Top-Level-Klassen_. ## Geschachtelte Klassen (Nested Classes) -Geschachtelte Klassen sind Top-Level-Klassen, die zur Strukturierung des -Namensraumes in anderen Top-Level-Klassen definiert sind. Ein Namensraum ist die -vollständige Pfadangabe zur Klasse (z.B. `java.lang`). Geschachtelte Klassen -müssen statisch definiert werden und sind daher im eigentlichen Sinne keine -richtigen inneren Klassen. +Geschachtelte Klassen sind statische Top-Level-Klassen, die innerhalb einer +anderen Top-Level-Klasse zur Strukturierung des Namensraums definiert werden. Da +sie statisch sein müssen, sind sie im eigentlichen Sinne keine echten inneren +Klassen. @@ -54,11 +53,11 @@ public class MainClass { ## Elementklassen (Member Classes) -Objekte von Elementklassen sind immer mit einem Objekt der umgebenden Klasse -verbunden. Dies ermöglicht die Umsetzung von Kompositionen (siehe +Objekte von Elementklassen sind immer an ein Objekt der umgebenden Klasse +gebunden. Das ermöglicht die Umsetzung von Kompositionen (siehe [Darstellung von Assoziationen](class-diagrams#darstellung-von-assoziationen)). -Sie haben Zugriff auf alle Variablen und Methoden der sie umgebenden Klasse und -dürfen keine statischen Elemente enthalten. +Elementklassen haben Zugriff auf alle Variablen und Methoden der umgebenden +Klasse, dürfen aber keine statischen Elemente enthalten. @@ -79,8 +78,8 @@ public class MainClass { public static void main(String[] args) { List list = new List(); - List.Item item = new List.Item(); // Kompilierungsfehler - List.Item item = list.new Item(); + List.Item item = new List.Item(); // Kompilierungsfehler: Elementklasse benötigt umgebendes Objekt + List.Item item = list.new Item(); // korrekt } } @@ -91,11 +90,10 @@ public class MainClass { ## Lokale Klassen -Lokale Klassen werden innerhalb einer Methode definiert und können auch nur dort -verwendet werden. Sie dürfen nicht als `public`, `protected`, `private` oder -`static` definiert werden, dürfen keine statischen Elemente enthalten und können -nur die mit `final` markierten Variablen und Parameter der umgebenden Methode -verwenden. +Lokale Klassen werden innerhalb einer Methode definiert und sind auch nur dort +verwendbar. Sie dürfen nicht als `public`, `protected`, `private` oder `static` +deklariert werden, dürfen keine statischen Elemente enthalten und können nur auf +`final`-markierte Variablen und Parameter der umgebenden Methode zugreifen. @@ -151,12 +149,11 @@ public class MainClass { ## Anonyme Klassen -Anonyme Klassen besitzen im Gegensatz zu lokalen Klassen keinen Namen und werden -innerhalb eines Ausdrucks definiert und instanziiert; Klassendeklaration und -Objekterzeugung sind also in einem Sprachkonstrukt vereint. Wird als Datentyp -eine Schnittstelle benötigt, implementiert die anonyme Klasse diese -Schnittstelle, wird als Datentyp eine Klasse benötigt, so wird die anonyme -Klasse daraus abgeleitet. +Anonyme Klassen haben im Gegensatz zu lokalen Klassen keinen Namen. Sie werden +direkt innerhalb eines Ausdrucks definiert und instanziiert — Klassendeklaration +und Objekterzeugung sind also in einem Konstrukt vereint. Ist der erwartete +Datentyp eine Schnittstelle, implementiert die anonyme Klasse diese; ist es eine +Klasse, wird daraus abgeleitet. diff --git a/docs/documentation/interfaces.mdx b/docs/documentation/interfaces.mdx index 03db25a094..d6950b328f 100644 --- a/docs/documentation/interfaces.mdx +++ b/docs/documentation/interfaces.mdx @@ -8,14 +8,13 @@ tags: [interfaces] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Wird eine Klasse von mehreren Klassen abgeleitet, spricht man von -Mehrfachvererbung. Das Prinzip der Mehrfachvererbung wird von vielen -Programmiersprachen allerdings nicht (direkt) unterstützt. Der Hauptgrund hier -sind mögliche Mehrdeutigkeiten. Erbt eine Klasse über mehrere mögliche Pfade von -einer Basisklasse und werden dabei möglicherweise Methoden der Basisklasse -unterschiedlich überschrieben, entstehen dadurch nicht eindeutige Varianten. -Aufgrund der Rautenform des Klassendiagramms wird dieses Szenario also -_Diamantenproblem_ bezeichnet. +Erbt eine Klasse von mehreren Klassen gleichzeitig, spricht man von +_Mehrfachvererbung_. Dieses Konzept wird von vielen Programmiersprachen nicht +direkt unterstützt, da es zu Mehrdeutigkeiten führen kann: Erbt eine Klasse über +mehrere Pfade von derselben Basisklasse und wurde dabei eine Methode +unterschiedlich überschrieben, entsteht Unklarheit, welche Implementierung +verwendet werden soll. Aufgrund der Rautenform im Klassendiagramm bezeichnet man +dieses Problem als _Diamantenproblem_. ```mermaid classDiagram @@ -36,17 +35,17 @@ classDiagram } ``` -Zur Lösung des Diamantenproblems werden Schnittstellen (Interfaces) verwendet. -Schnittstellen sind im Prinzip abstrakte Klassen, die ausschließlich abstrakte -Methoden besitzen. Durch Schnittstellen wird sichergestellt, dass Klassen -bestimmte Methoden bereitstellen und dass verschiedene Klassen miteinander -kommunizieren können. +Zur Lösung des Diamantenproblems werden Schnittstellen (Interfaces) eingesetzt. +Schnittstellen sind im Wesentlichen abstrakte Klassen, die ausschließlich +abstrakte Methoden enthalten. Sie stellen sicher, dass implementierende Klassen +bestimmte Methoden bereitstellen, ohne eine konkrete Vererbungshierarchie +vorzuschreiben. ## Definition von Schnittstellen -Die Definition einer Schnittstelle erfolgt analog zur Definition von Klassen. -Das Schlüsselwort für Schnittstellen lautet `interface`. Eine Schnittstelle kann -nur öffentliche, abstrakte und öffentliche, statische Methoden beinhalten. +Eine Schnittstelle wird ähnlich wie eine Klasse definiert, verwendet aber das +Schlüsselwort `interface`. Sie kann nur öffentliche abstrakte sowie öffentliche +statische Methoden enthalten. ```java title="MobileDevice.java" showLineNumbers public interface MobileDevice { @@ -64,9 +63,9 @@ Die Angabe von `abstract` und `public` bei Methoden ist nicht erforderlich. ## Implementieren von Schnittstellen -Schnittstellen werden mit Hilfe des Schlüsselworts `implements` von einer Klasse -implementiert. Durch die Implementierung der Schnittstelle verpflichtet sich die -Klasse, alle Methoden der Schnittstelle zu implementieren. +Eine Schnittstelle wird mit dem Schlüsselwort `implements` von einer Klasse +implementiert. Damit verpflichtet sich die Klasse, alle Methoden der +Schnittstelle zu implementieren. @@ -98,9 +97,9 @@ public class Notebook extends Computer implements MobileDevice { ## Verwenden von Schnittstellen -Schnittstellen können ebenso wie Klassen als Datentypen verwendet werden. Die +Schnittstellen können wie Klassen als Datentypen verwendet werden. Die Typumwandlung von der implementierenden Klasse zur Schnittstelle bezeichnet man -als _Upcast_ die Rückumwandlung als _Downcast_ +als _Upcast_, die Rückumwandlung als _Downcast_. diff --git a/docs/documentation/introduction.mdx b/docs/documentation/introduction.mdx index 870bc61162..1e307f40bd 100644 --- a/docs/documentation/introduction.mdx +++ b/docs/documentation/introduction.mdx @@ -10,24 +10,23 @@ import Contributor from '@site/src/components/Contributor'; # Einführung -1995 veröffentliche die Firma Sun Microsystems die Programmiersprache Java. -Diese hat sich im Laufe der Zeit als universelle, für vielfältige Zwecke -einsetzbare Lösung und als Quasi-Standard für die plattformunabhängige -Entwicklung etabliert. Zudem war Java einer der maßgeblichen Wegbereiter für die -Verbreitung des objektorientierten Programmierparadigmas, welches gemeinhin in -vielen Bereichen als State-of-the-Art gilt. +1995 veröffentlichte die Firma Sun Microsystems die Programmiersprache Java. Sie +hat sich seitdem als universelle, vielseitig einsetzbare Lösung und als +Quasi-Standard für die plattformunabhängige Softwareentwicklung etabliert. Zudem +war Java einer der wichtigsten Wegbereiter für die Verbreitung des +objektorientierten Programmierparadigmas, das heute in vielen Bereichen als +Stand der Technik gilt. -Diese Webseite sowie die dazugehörigen Vorlesungen sollen eine systematische -Einführung in das Programmieren mit Java ermöglichen. Hierzu werden wichtige, -praxisrelevante Konzepte und Methoden der Programmierung vorgestellt, wobei die -objektorientierte Programmierung einen großen Raum einnimmt. +Diese Webseite und die dazugehörigen Vorlesungen bieten eine systematische +Einführung in das Programmieren mit Java. Es werden wichtige, praxisrelevante +Konzepte und Methoden der Programmierung vorgestellt, wobei die +objektorientierte Programmierung einen großen Schwerpunkt bildet. -Wir stellen grundsätzliche alle Inhalte der Vorlesung (Dokumentation, -Abbildungen, Quellcode) in Textform bereit (_Everything as Code_). Da -professionelle Softwareentwicklung immer auch Zusammenarbeit bedeutet, möchten -wir zudem auf moderne Art und Weise (z.B. per Issues, Pull Requests oder -Discussions) die Studierenden zu eben dieser Zusammenarbeit animieren -(_Community by Design_). +Alle Inhalte der Vorlesung (Dokumentation, Abbildungen, Quellcode) werden in +Textform bereitgestellt (_Everything as Code_). Da professionelle +Softwareentwicklung immer auch Zusammenarbeit bedeutet, werden Studierende +eingeladen, auf moderne Art und Weise — z.B. per Issues, Pull Requests oder +Discussions — aktiv mitzuwirken (_Community by Design_). ## Contributors diff --git a/docs/documentation/io-streams.md b/docs/documentation/io-streams.md index b777a56fa0..60f12197d9 100644 --- a/docs/documentation/io-streams.md +++ b/docs/documentation/io-streams.md @@ -5,17 +5,13 @@ sidebar_position: 340 tags: [io-streams] --- -Datenströme (IO-Streams) sind unidirektionale Pipelines, die Schnittstellen -eines Java-Programms nach außen darstellen. Daten können unabhängig von der Art -der Quelle bzw. des Ziels vorne in einen Datenstrom geschrieben und hinten -wieder ausgelesen werden. Ein Datenstrom kann dabei immer nur in eine Richtung -verwendet werden (also entweder zur Ein- oder Ausgabe). Neben den -Standard-Datenströmen zur Ein- und Ausgabe existieren verschiedene Klassen zum -Schreiben und Lesen zeichenorientierter Daten, zum Schreiben und Lesen -byteorientierter Daten und zum Schreiben und Lesen serialisierter Objekte. Das -Arbeiten mit Datenstrom-Klassen kann dabei aufwändig über "normale" -try-catch-Anweisungen oder mit Hilfe von try-with-resources-Anweisungen -realisiert werden. +Datenströme (IO-Streams) sind unidirektionale Pipelines zwischen einem +Java-Programm und einer Datenquelle oder einem Datenziel. Daten werden vorne in +den Strom geschrieben und hinten wieder ausgelesen. Ein Datenstrom kann dabei +immer nur in eine Richtung verwendet werden — entweder zur Eingabe oder zur +Ausgabe. Java bietet Klassen für zeichenorientierte Daten (z.B. Textdateien), +byteorientierte Daten (z.B. Bilddateien) und serialisierte Objekte. Für das +korrekte Schließen der Ströme empfiehlt sich die `try-with-resources`-Anweisung. ```mermaid flowchart LR @@ -29,8 +25,9 @@ flowchart LR ## Standard-Datenströme zur Ein- und Ausgabe -Java stellt Standard-Datenströme für die Eingabe (`System.in`), die Ausgabe -(`System.out`), sowie die Fehlerausgabe (`System.err`) zur Verfügung. +Java stellt drei Standard-Datenströme bereit: `System.in` für die +Standardeingabe (Tastatur), `System.out` für die Standardausgabe (Konsole) und +`System.err` für die Fehlerausgabe. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -64,9 +61,8 @@ ermöglicht eine einfache Möglichkeit der Eingabe. ## Schreiben und Lesen byteorientierter Daten -Für die Verarbeitung von byteorientierten Daten (z.B. Bild- und Video-Dateien) -stehen die abstrakten Basisklassen `InputStream` und `OutputStream` zur -Verfügung. +Für die Verarbeitung byteorientierter Daten wie Bild- oder Videodateien stehen +die abstrakten Basisklassen `InputStream` und `OutputStream` zur Verfügung. | Datenstromklasse | Ein- und Ausgabe in... | | ------------------------------------------------ | ---------------------- | @@ -125,8 +121,8 @@ public class MainClass { ## Schreiben und Lesen zeichenorientierter Daten -Für die Verarbeitung von zeichenorientierten Daten (z.B. Textdokumente) stehen -die abstrakten Basisklassen `Reader` und `Writer` zur Verfügung. +Für die Verarbeitung zeichenorientierter Daten wie Textdateien stehen die +abstrakten Basisklassen `Reader` und `Writer` zur Verfügung. | Datenstromklasse | Ein- und Ausgabe in... | | ------------------------------------- | ---------------------- | @@ -187,18 +183,15 @@ public class MainClass { ## Schreiben und Lesen serialisierter Objekte -Um ein Objekt persistent zu machen (also zu sichern) und um ein Objekt durch das -Netzwerk zu schicken (also für entfernte Methodenaufrufe) ist es notwendig, das -Objekt in einen Byte-Strom umzuwandeln. Die Umwandlung eines Objektes in einen -Byte-Strom bezeichnet man als _Serialisierung_ die Rückumwandlung als -_Deserialisierung_ Die Serialisierung erfolgt über die writeObject-Methode der -Klasse `ObjectOutputStream`, die Deserialisierung über die readObject-Methode -der Klasse `ObjectInputStream`. +Serialisierung bezeichnet die Umwandlung eines Objekts in einen Byte-Strom, z.B. +zum Speichern in einer Datei oder zum Versenden über ein Netzwerk. Der +umgekehrte Vorgang wird als _Deserialisierung_ bezeichnet. Die Serialisierung +erfolgt mit der Methode `writeObject()` der Klasse `ObjectOutputStream`, die +Deserialisierung mit `readObject()` der Klasse `ObjectInputStream`. -Damit Objekte einer Klasse serialisiert werden können, muss die entsprechende -Klasse die Schnittstelle `Serializable` implementieren. Die Schnittstelle -`Serializable` ist eine sogenannte Marker-Schnittstelle, d.h. sie besitzt keine -zu implementierenden Methoden. +Damit Objekte einer Klasse serialisiert werden können, muss die Klasse die +Schnittstelle `Serializable` implementieren. Diese sogenannte +Marker-Schnittstelle besitzt keine zu implementierenden Methoden. ```java title="Foo.java" showLineNumbers public record Stark(String name) implements Serializable {} @@ -248,31 +241,31 @@ public class MainClass { ```java title="MainClass.java" showLineNumbers public class MainClass { - public static void main(String[] args) { - File file = new File("starks.bin"); + public static void main(String[] args) { + File file = new File("starks.bin"); - try (FileInputStream fis = new FileInputStream(file); - ObjectInputStream ois = new ObjectInputStream(fis)) { - while (true) { - Stark stark = (Stark) ois.readObject(); - System.out.println(stark); + try (FileInputStream fis = new FileInputStream(file); + ObjectInputStream ois = new ObjectInputStream(fis)) { + while (true) { + Stark stark = (Stark) ois.readObject(); + System.out.println(stark); + } + } catch (EOFException e) { + // Dateiende erreicht + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); } - } catch (EOFException e) { - /* End of File */ - } catch (IOException | ClassNotFoundException e) { - e.printStackTrace(); - } - } + } } ``` ### Versionierung bei der Serialisierung -Die Konstante `serialVersionUID` vom Datentyp `long` dient zur eindeutigen -Identifikation der Version einer serialisierbaren Klasse. Durch die Konstante -kann sichergestellt werden, dass Empfänger von serialisierten Objekten -typkompatibel zum Sender sind, d.h. eine passende Klassenstruktur aufweisen. +Die Konstante `serialVersionUID` vom Typ `long` identifiziert eindeutig die +Version einer serialisierbaren Klasse. Sie stellt sicher, dass eine +deserialisierte Klasse dieselbe Struktur besitzt wie die ursprünglich +serialisierte Klasse. ```java title="Foo.java" showLineNumbers public record Stark(String name) implements Serializable { @@ -291,8 +284,8 @@ Zuweisung dringend empfohlen. ## Die try-with-resources-Anweisung -Bei einer "normalen" try-catch-Anweisung müssen die Datenstrom-Klassen manuell -geschlossen werden, was sich als sehr aufwändig darstellt. +Bei einer gewöhnlichen `try-catch`-Anweisung müssen Datenstrom-Objekte manuell +im `finally`-Block geschlossen werden, was schnell unübersichtlich wird. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -328,8 +321,8 @@ Der finally-Block einer try-Anweisung wird in jedem Fall durchlaufen. ::: -Die try-with-resources-Anweisung ermöglicht die Deklaration von Ressourcen, die -am Ende des try-Blockes automatisch geschlossen werden. +Die `try-with-resources`-Anweisung deklariert Ressourcen direkt im `try`-Kopf +und schließt sie automatisch am Ende des Blocks. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -350,7 +343,7 @@ public class MainClass { :::info -Voraussetzung für den Einsatz der try-with-resources-Anweisung ist, dass die -Ressourcen-Klassen die Schnittstelle `AutoCloseable` implementiert haben. +Voraussetzung für den Einsatz der `try-with-resources`-Anweisung ist, dass die +verwendeten Klassen die Schnittstelle `AutoCloseable` implementieren. ::: diff --git a/docs/documentation/java-api.md b/docs/documentation/java-api.md index 239c25350c..3bba992e69 100644 --- a/docs/documentation/java-api.md +++ b/docs/documentation/java-api.md @@ -5,11 +5,12 @@ sidebar_position: 140 tags: [java-api] --- -Die _Java API_ (Java Application Programming Interface) stellt eine umfangreiche -Bibliothek wichtiger Java-Klassen dar. Neben dem eigentlichen Quellcode stellt -die Java API auch detaillierte Informationen zu den Klassen (Paketzugehörigkeit, -Attribute, Methoden,…) als Javadoc bereit. Entwicklungsumgebungen wie Eclipse -bieten meist eine vollständige Integration der Java API an. +Die _Java API_ (Application Programming Interface) ist eine umfangreiche +Standardbibliothek, die fertige Klassen und Schnittstellen für häufige +Programmieraufgaben bereitstellt. Zusätzlich zum Quellcode enthält die Java API +eine Javadoc-Dokumentation mit Informationen zu Paketen, Klassen, Attributen und +Methoden. Entwicklungsumgebungen wie Eclipse oder IntelliJ IDEA integrieren die +Java API direkt in die Code-Vervollständigung. ## Wichtige Klassen und Schnittstellen der Java API @@ -36,14 +37,13 @@ bieten meist eine vollständige Integration der Java API an. ## Die Javadoc -Die Javadoc ist ein Werkzeug zur Software-Dokumentation und erstellt aus den +Die Javadoc ist ein Werkzeug zur Software-Dokumentation. Es erstellt aus den öffentlichen Deklarationen von Klassen, Schnittstellen, Attributen und Methoden -sowie eventuell vorhandenen +sowie optionalen [Dokumentationskommentaren](class-structure#kommentare-und-dokumentation) -HTML-Seiten. Um die Navigation innerhalb der Dokumentationsdateien zu -erleichtern, werden zusätzlich verschiedene Index- und Hilfsdateien generiert. -HTML-Tags in den Dokumentationskommentaren ermöglichen die Formatierung der -Dokumentation. +HTML-Seiten. Zur einfacheren Navigation werden zusätzlich Index- und +Hilfsdateien generiert. HTML-Tags in den Kommentaren ermöglichen die +Formatierung der Dokumentation. ```java title="Computer.java (Auszug)" showLineNumbers /** diff --git a/docs/documentation/java-collections-framework.mdx b/docs/documentation/java-collections-framework.mdx index ba26a00a9e..0fcfac0849 100644 --- a/docs/documentation/java-collections-framework.mdx +++ b/docs/documentation/java-collections-framework.mdx @@ -8,20 +8,17 @@ tags: [collections, lists, sets, queues] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Collections sind Behälter, die beliebig viele Objekte aufnehmen können. Der -Behälter übernimmt dabei die Verantwortung für die Elemente. Collections werden -auch als (Daten-)Sammlungen bezeichnet. Alle Collections-Schnittstellen und -Klassen befinden sich im Paket `java.util`. Die Grundformen der Datensammlungen -sind die Schnittstellen `List`, `Set` und `Queue`. Zu allen -Schnittstellen existieren konkrete Implementierungen sowie abstrakte Klassen, -die zum Erstellen eigener Collections-Klassen verwendet werden können. +Das Java Collections Framework stellt Schnittstellen und Klassen für +Datensammlungen bereit. Alle Collections-Typen befinden sich im Paket +`java.util`. Die drei Grundformen sind `List`, `Set` und `Queue`, zu +denen jeweils konkrete Implementierungen existieren. -Unter einer Liste (List) versteht man eine geordnete Folge von Objekten. Listen -können doppelte Elemente enthalten. Der Zugriff auf die Elemente erfolgt über -den Index oder sequentiell. +Eine Liste ist eine geordnete Folge von Objekten, die doppelte Elemente +enthalten darf. Der Zugriff auf die Elemente erfolgt über den Index oder +sequentiell. ```mermaid flowchart @@ -40,9 +37,9 @@ Konkrete Implementierungen der Schnittstelle `List` stellen die Klassen -Unter einer Menge (Set) versteht man eine Ansammlung von Elementen. Mengen -können keine doppelten Elemente beinhalten. Der Zugriff erfolgt über typische -Mengenoperationen. +Eine Menge ist eine Ansammlung von Objekten, die keine doppelten Elemente +enthalten darf. Der Zugriff erfolgt über typische Mengenoperationen wie +Vereinigung, Schnittmenge und Differenz. ```mermaid flowchart LR @@ -61,11 +58,10 @@ Binärbaumes. -Unter einer Warteschlange (Queue) versteht man eine Folge von Objekten, bei der -das Anfügen und Löschen von Objekten nach dem FIFO-Prinzip (First In First Out) -funktioniert. Bei einer Warteschlange kann ein neues Objekt immer nur am Ende -angefügt werden und nur das Objekt, das am Anfang der Warteschlange steht, -gelöscht werden. Warteschlangen können doppelte Elemente enthalten. +Eine Warteschlange ist eine Folge von Objekten, bei der Elemente nach dem +FIFO-Prinzip (First In, First Out) verwaltet werden: Neue Elemente werden am +Ende eingefügt, entnommen wird immer das vorderste Element. Doppelte Elemente +sind erlaubt. ```mermaid flowchart LR @@ -80,22 +76,20 @@ flowchart LR name5(Max) ``` -Konkrete Implementierungen der Schnittstelle `Queue` stellen die Klassen -`PriorityQueue` und `LinkedList` dar. Die Klasse `PriorityQueue` -implementiert die Warteschlange als eine Vorrang-Warteschlange. Bei einer -Vorrang-Warteschlange werden die Elemente gemäß ihrer Wichtigkeit sortiert, das -heißt, sie funktioniert nicht nach dem FIFO-Prinzip. +Konkrete Implementierungen der Schnittstelle `Queue` sind `PriorityQueue` +und `LinkedList`. Die Klasse `PriorityQueue` implementiert eine +Vorrang-Warteschlange, bei der die Elemente nicht nach dem FIFO-Prinzip, sondern +nach ihrer Wichtigkeit sortiert entnommen werden. ## Iteratoren -Ein Iterator erlaubt den sequentiellen Zugriff auf die Elemente einer -Datensammlung. Iteratoren werden durch die Schnittstelle `Iterator` -definiert; diese bietet die Methoden `boolean hasNext()`, `E next()` und -`void remove()`. Die von `Iterator` abgeleitete Schnittstelle -`ListIterator` bietet zusätzliche Methoden zum Verändern einer Liste. +Ein Iterator ermöglicht den sequentiellen Zugriff auf die Elemente einer +Datensammlung, ohne die interne Struktur kennen zu müssen. Die Schnittstelle +`Iterator` bietet die Methoden `boolean hasNext()`, `E next()` und +`void remove()`. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -115,9 +109,9 @@ public class MainClass { } ``` -Auch die bereits bekannte for-each-Schleife basiert auf Iteratoren. Die -ausführliche Schreibeweise mit Iteratoren wird auch als erweiterte for-Schleife -bezeichnet. Beim Kompilieren werden for-each-Schleifen um Iteratoren ergänzt. +Auch die bereits bekannte for-each-Schleife basiert intern auf Iteratoren. Beim +Kompilieren wird sie automatisch in eine Iterator-Schleife umgewandelt. Die +ausführliche Schreibweise ist daher gleichwertig zur Kurzschreibweise. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -126,12 +120,13 @@ public class MainClass { List names = List.of("Hans", "Peter", "Lisa"); + // Ausführliche Schreibweise mit Iterator for (Iterator iterator = names.iterator(); iterator.hasNext();) { String name = iterator.next(); System.out.println(name); } - /* Kurzschreibweise */ + // Kurzschreibweise mit for-each for (String name : names) { System.out.println(name); } diff --git a/docs/documentation/java-stream-api.md b/docs/documentation/java-stream-api.md index 9d17c3ab08..67c36ee893 100644 --- a/docs/documentation/java-stream-api.md +++ b/docs/documentation/java-stream-api.md @@ -5,14 +5,12 @@ sidebar_position: 300 tags: [java-stream-api] --- -Die Java Stream API stellt Klassen zum Erzeugen von und Arbeiten mit Strömen -(Streams) bereit. Ein Strom stellt eine Folge von Elementen dar, die das -Ausführen verketteter, intermediärer und terminaler Operationen auf diesen -Elementen nacheinander oder parallel ermöglicht. Die Daten, die durch die -Elemente des Stromes repräsentiert werden, werden dabei durch den Strom selbst -nicht verändert. Die Verarbeitung der Elemente erfolgt nach dem Prinzip der -Bedarfsauswertung (Lazy Evaluation). Neben endlichen Strömen stellt die Java -Stream API auch Methoden zum Erzeugen unendlicher Ströme bereit. +Die Java Stream API ermöglicht die funktionale Verarbeitung von Elementfolgen. +Ein Strom (Stream) repräsentiert eine Sequenz von Elementen, auf der verkettete +Operationen ausgeführt werden können — entweder sequentiell oder parallel. Die +Originaldaten bleiben dabei unverändert. Die Auswertung erfolgt nach dem Prinzip +der Bedarfsauswertung (Lazy Evaluation): Operationen werden erst dann +ausgeführt, wenn eine terminale Operation dies erfordert. ```mermaid flowchart TD @@ -52,8 +50,7 @@ Ströme (Paket `java.util.stream`) haben nichts mit ## Erzeugen von Strömen -Ströme können unter anderem aus Feldern, Datensammlungen wie z.B. Listen und -Mengen sowie Einzelobjekten erzeugt werden. +Ströme lassen sich aus Feldern, Listen, Mengen oder einzelnen Werten erzeugen. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -71,16 +68,16 @@ public class MainClass { } ``` -:::info +:::note Die Zahlenfolge 4-8-15-16-23-42 spielt eine große Rolle in der Fernsehserie _Lost_. ::: -Im Gegensatz zu "normalen" Strömen besitzen Objekte der Klassen `IntStreams`, -`DoubleStreams` und `LongStreams` Methoden zur Weiterverarbeitung ihrer -primitiver Werte. +Im Gegensatz zu `Stream` bieten die spezialisierten Klassen `IntStream`, +`DoubleStream` und `LongStream` zusätzliche Methoden zur Verarbeitung primitiver +Werte, wie etwa `sum()` oder `average()`. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -96,15 +93,16 @@ public class MainClass { ## Intermediäre Operationen -Intermediäre Operationen ermöglichen unter anderem das Filtern, Abbilden sowie -das Sortieren von Strömen und liefern als Ergebnis wiederum einen Strom. +Intermediäre Operationen transformieren einen Strom in einen neuen Strom. Sie +werden erst dann ausgeführt, wenn eine terminale Operation folgt. Typische +intermediäre Operationen sind Filtern, Abbilden und Sortieren. | Operation | Methode | Schnittstellen-Methode | | ------------- | ---------------------------------------------------------- | -------------------------------- | | Filtern | `Stream filter(predicate: Predicate)` | `boolean test(t: T)` | | Abbilden | `Stream map(mapper: Function)` | `R apply(t: T)` | | Abbilden | `DoubleStream mapToDouble(mapper: ToDoubleFunction)` | `double applyAsDouble(value: T)` | -| Abbilden | `IntStream mapToInt(mapper: ToIntFunction)` | `int applyAsInt(vaue: T)` | +| Abbilden | `IntStream mapToInt(mapper: ToIntFunction)` | `int applyAsInt(value: T)` | | Abbilden | `LongStream mapToLong(mapper: ToLongFunction)` | `long applyAsLong(value: T)` | | Spähen | `Stream peek(consumer: Consumer)` | `void accept(t: T)` | | Sortieren | `Stream sorted(comparator: Comparator)` | `int compare(o1: T, o2: T)` | @@ -114,9 +112,10 @@ das Sortieren von Strömen und liefern als Ergebnis wiederum einen Strom. ## Terminale Operationen -Terminale Operationen werden z.B. zum Prüfen, zum Aggregieren oder zum Sammeln -verwendet. Da terminale Operationen den Strom schließen, können auf ihnen keine -weiteren Operationen mehr ausgeführt werden. +Terminale Operationen schließen den Strom ab und liefern ein Ergebnis. Da der +Strom danach nicht mehr verwendbar ist, können keine weiteren Operationen +folgen. Typische Anwendungsfälle sind das Prüfen, Aggregieren und Sammeln von +Elementen. | Operation | Methode | Schnittstellen-Methode | | ----------- | -------------------------------------------- | --------------------------- | @@ -131,22 +130,20 @@ weiteren Operationen mehr ausgeführt werden. | Sammeln | `R collect(collector: Collector)` | - | | Ausführen | `void forEach(action: Consumer)` | `void accept(t: T)` | -Zahlenströme (`IntStream`, `DoubleStream`, `LongStream`) besitzen die -zusätzlichen terminale Operationen `int|double|long sum()` und -`OptionalDouble average()`. +Zahlenströme (`IntStream`, `DoubleStream`, `LongStream`) bieten zusätzlich die +terminalen Operationen `sum()` und `average()`. ## Bedarfsauswertung (Lazy Evaluation) -Die Elemente in Strömen werden nur bei Bedarf ausgewertet. Intermediäre -Operationen werden also nur dann ausgeführt, wenn eine terminale Operation -vorhanden ist und bei verketteten Operationen werden für jedes Element die -einzelnen Operationen nacheinander ausgeführt. +Bei der Bedarfsauswertung werden intermediäre Operationen nicht sofort +ausgeführt, sondern erst dann, wenn eine terminale Operation den Strom +abschließt. Zudem werden bei verketteten Operationen alle Schritte für jedes +Element nacheinander durchlaufen — nicht erst alle Elemente durch Schritt 1, +dann alle durch Schritt 2. -In der main-Methode der Startklasse wird auf den Zahlenstrom 4-8-15-16-23-42 -zunächst der Filter _Zahl = ganze Zahl_ angewendet, anschließend der Filter -_Zahl > 15_ und abschließend werden die verbliebenen Zahlen auf der Konsole -ausgegeben. Zum Nachvollziehen werden die Zahlen auch bei den beiden Filtern auf -der Konsole ausgegeben. +Das folgende Beispiel filtert den Zahlenstrom 4-8-15-16-23-42 zunächst nach +geraden Zahlen, dann nach Zahlen größer als 15, und gibt die verbliebenen Zahlen +aus. Zur Veranschaulichung wird jeder Filterschritt ebenfalls ausgegeben. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -164,9 +161,8 @@ public class MainClass { } ``` -Ohne Bedarfsauswertung würden die verschiedenen Operationen für die jeweils -verbliebenen Elemente ausgeführt nacheinander werden. Die Ausgabe sähe wie folgt -aus: +Ohne Bedarfsauswertung würden die Operationen nacheinander für alle Elemente +ausgeführt: ``` 4: filter 1 @@ -183,9 +179,8 @@ aus: 42: forEach ``` -Aufgrund der Bedarfsauswertung werden die verschiedenen Operationen aber für -jedes Element einzeln nacheinander ausgeführt. Dadurch ergibt sich folgende -Ausgabe: +Aufgrund der Bedarfsauswertung werden alle Operationen für jedes Element einzeln +nacheinander ausgeführt: ``` 4: filter 1 @@ -204,36 +199,32 @@ Ausgabe: ## Unendliche Ströme -Die Java Stream API stellt drei Methoden zur Verfügung, mit deren Hilfe -(un)endliche Ströme erzeugt werden können: - -- Die Methode `Stream iterate(seed: T, f: UnaryOperator)` generiert einen - unendlichen Strom aus einem Startwert und einer Funktion, welche das nächste - Element erstellt -- Die Methode - `Stream iterate(seed: T, hasNext: Predicat , next: UnaryOperator)` - erweitert die "normale" iterate-Methode um eine Prädikatsfunktion zum Beenden - des Stroms -- Die Methode `Stream generate(s: Supplier)` kann zum Beispiel zum - Erzeugen unendlich vieler zufälliger Elemente genutzt werden +Die Java Stream API stellt Methoden bereit, mit denen sich theoretisch unendlich +viele Elemente erzeugen lassen. In der Praxis werden solche Ströme durch +`limit()` begrenzt. -In der main-Methode der Startklasse werden drei (un)endliche Zahlenströme -erzeugt. +- `Stream iterate(seed: T, f: UnaryOperator)` — erzeugt einen unendlichen + Strom aus einem Startwert und einer Funktion, die jeweils das nächste Element + berechnet +- `Stream iterate(seed: T, hasNext: Predicate, next: UnaryOperator)` — + wie oben, aber mit einer Abbruchbedingung +- `Stream generate(s: Supplier)` — erzeugt Elemente über einen + Lieferanten, z.B. Zufallszahlen ```java title="MainClass.java" showLineNumbers public class MainClass { public static void main(String[] args) { + // Zahlen 0 bis 99 ausgeben (unendlicher Strom, begrenzt auf 100) Stream.iterate(0, i -> ++i).limit(100).forEach(System.out::println); + // Zahlen 0 bis 99 mit Abbruchbedingung Stream.iterate(0, i -> i < 100, i -> ++i).forEach(System.out::println); + // 100 Pseudozufallszahlen von 0 bis 99 Stream.generate(() -> new Random().nextInt(100)).limit(100).forEach(System.out::println); } } ``` -Die ersten beiden Zahlenströme geben die Zahlen von 0 bis 99 aus, der dritte -Zahlenstrom 100 Pseudozufallszahlen von 0 bis 99. Der erste und dritte -Zahlenstrom würden eigentlich unendliche viele (Pseudozufalls-)Zahlen erzeugen, -werden aber durch die Methode `Stream limit(maxSize: long)` auf 100 -(Pseudozufalls-)Zahlen begrenzt. +Die ersten beiden Ströme geben die Zahlen von 0 bis 99 aus. Der dritte erzeugt +100 Pseudozufallszahlen von 0 bis 99 und wird durch `limit(100)` begrenzt. diff --git a/docs/documentation/java.md b/docs/documentation/java.md index 3cb0510d2e..3733ed7aea 100644 --- a/docs/documentation/java.md +++ b/docs/documentation/java.md @@ -6,28 +6,27 @@ tags: [java] --- Die Programmiersprache Java gehört zu den problemorientierten -Programmiersprachen und ist daher einfacher zu erlernen und einfacher zu -verstehen als maschinenorientierte Programmiersprachen. Bei der Entwicklung von -Java verfolgte man das Ziel, eine einfache, objektorientierte, robuste, -architekturneutrale und parallelisierbare Programmiersprache zu entwickeln. Java -wurde hauptsächlich von C und C++ beeinflusst, ist allerdings im Gegensatz zu C -und C++ nicht darauf ausgelegt, möglichst leistungsfähige Programme zu erzeugen, -sondern möglichst sichere und fehlerfreie Programme. +Programmiersprachen und ist daher einfacher zu erlernen und zu verstehen als +maschinenorientierte Sprachen. Bei der Entwicklung von Java verfolgte man das +Ziel, eine einfache, objektorientierte, robuste, architekturneutrale und +parallelisierbare Sprache zu schaffen. Java wurde hauptsächlich von C und C++ +beeinflusst, legt aber im Gegensatz zu diesen weniger Wert auf maximale +Leistung, sondern vor allem auf Sicherheit und Fehlerfreiheit. ## Die Geschichte von Java -Anfang der 90er begannen bei der Firma Sun Microsystems unter Federführung des -Chefentwicklers James Gosling die Arbeiten an einem Projekt mit dem Codenamen -_The Green Project_ mit dem Ziel, eine vollständige Betriebssystemumgebung für -unterschiedliche Zwecke (interaktives Kabelfernsehen, intelligente -Kaffeemaschinen etc.) zu entwickeln. Die daraus entstehende Programmiersprache +Anfang der 1990er Jahre startete bei der Firma Sun Microsystems unter der +Leitung von Chefentwickler James Gosling ein Projekt mit dem Codenamen _The +Green Project_. Ziel war es, eine vollständige Betriebssystemumgebung für +unterschiedliche Anwendungsfälle (interaktives Kabelfernsehen, intelligente +Haushaltsgeräte etc.) zu entwickeln. Die daraus entstehende Programmiersprache sollte ursprünglich den Namen _Oak_ (Object Application Kernel) tragen, wurde -aber schließlich im Mai 1995 unter dem Namen _Java_ veröffentlicht. Der große -Durchbruch von Java kam 1996 durch eine Kooperation mit der Firma Netscape -zustande, die eine Integration von Java-Applets mit Hilfe von JavaScript in den -Browser Netscape Navigator 2.0 ermöglichte. Weitere wichtige Meilensteine in der -Geschichte von Java waren die Veröffentlichungen der Google-Entwicklungsumgebung -Android 2008 sowie des Computerspiels Minecraft 2009. +aber schließlich im Mai 1995 unter dem Namen _Java_ veröffentlicht. Der +Durchbruch gelang 1996 durch eine Kooperation mit der Firma Netscape, die eine +Integration von Java-Applets in den Browser Netscape Navigator 2.0 ermöglichte. +Weitere wichtige Meilensteine waren die Veröffentlichung der +Android-Entwicklungsumgebung von Google (2008) sowie des Computerspiels +Minecraft (2009). :::info @@ -37,43 +36,40 @@ Java war der Name der beliebtesten Kaffeesorte der Entwickler. ## JDK und JRE -Das JDK (Java Development Kit) stellt die wichtigste Komponente zum -Programmieren von Java-Programmen dar. Es enthält neben dem Compiler und -Debugger weitere wichtige Werkzeuge sowie umfangreiche Bibliotheken (siehe -[Die Java API](java-api)). Die JRE (Java Runtime Environment) enthält den -Interpreter (die _Java Virtual Machine_) und wird zum Ausführen von -Java-Applikationen benötigt. Seit September 2017 wird alle sechs Monate eine -neue JDK-Version veröffentlicht (i.d.R. Mitte März und Mitte September eines -Jahres). Diese Versionen werden von Oracle nur bis zum Erscheinen der jeweils -nächsten Version unterstützt. Eine Ausnahme bilden hier die LTS-Versionen -(long-term-support-releases). Die aktuellen LTS-Versionen sind 8, 11, 17 und 21. +Das _Java Development Kit_ (JDK) ist die wichtigste Komponente zur Entwicklung +von Java-Programmen. Es enthält neben dem Compiler und Debugger weitere +Werkzeuge sowie umfangreiche Bibliotheken (siehe [Die Java API](java-api)). Die +_Java Runtime Environment_ (JRE) enthält den Interpreter (die _Java Virtual +Machine_) und wird zum Ausführen von Java-Programmen benötigt. Seit September +2017 erscheint alle sechs Monate eine neue JDK-Version (in der Regel Mitte März +und Mitte September). Diese Versionen werden von Oracle nur bis zum Erscheinen +der jeweils nächsten Version unterstützt. Eine Ausnahme bilden die LTS-Versionen +(Long-Term-Support-Releases). Die aktuellen LTS-Versionen sind 8, 11, 17 und 21. Die Neuerungen einer Version werden durch sogenannte JEPs (JDK Enhancement Proposals) festgelegt. Weitere Informationen zu den verschiedenen JDK-Versionen -können auf der offziellen [JDK-Seite](https://jdk.java.net/) gefunden werden. +sind auf der offiziellen [JDK-Seite](https://jdk.java.net/) zu finden. ## Entwicklung von Java-Programmen -Zur Entwicklung von Java-Programmen wird neben dem _Java Development Kit_ (JDK) -nur ein einfacher Texteditor benötigt. Das Kompilieren und Ausführen der Klassen -erfolgt dann über die Kommandozeile (Command Line Interface, kurz CLI). -Alternativ kann auch eine Entwicklungsumgebung (Integrated Development -Environment, kurz IDE) verwendet werden. Diese bieten in der Regel zusätzliche -Komfortfunktionen wie Syntaxhighlighting, Autovervollständigung, -Vorschlagslisten etc. und vereinfachen so die Entwicklung von Programmen. Die am -weitesten verbreiteten Entwicklungsumgebungen im Java-Umfeld sind dabei -[IntelliJ IDEA](https://www.jetbrains.com/idea/) und +Zur Entwicklung von Java-Programmen wird neben dem JDK nur ein einfacher +Texteditor benötigt. Das Kompilieren und Ausführen erfolgt dann über die +Kommandozeile (Command Line Interface, kurz CLI). Alternativ kann eine +Entwicklungsumgebung (Integrated Development Environment, kurz IDE) verwendet +werden. Diese bietet in der Regel zusätzliche Komfortfunktionen wie +Syntaxhervorhebung, Autovervollständigung und Vorschlagslisten, was die +Entwicklung deutlich erleichtert. Die am weitesten verbreiteten IDEs im +Java-Umfeld sind [IntelliJ IDEA](https://www.jetbrains.com/idea/) und [Eclipse IDE](https://www.eclipse.org/). ## Programmierstil (Code Style) Als Programmierstil (Code Style) bezeichnet man alle Regeln und Richtlinien, die -Entwickler befolgen sollten, um sicherzustellen, dass ihr Quellcode konsistent, -gut lesbar und leicht wartbar ist. Ein einheitlicher Programmierstil erleichtert -so auch die Zusammenarbeit in Teams, da er die Verständlichkeit und Wartbarkeit -des Codes verbessert. +Entwicklerinnen und Entwickler befolgen sollten, um sicherzustellen, dass ihr +Quellcode konsistent, gut lesbar und leicht wartbar ist. Ein einheitlicher +Programmierstil erleichtert auch die Zusammenarbeit in Teams, da er die +Verständlichkeit und Wartbarkeit des Codes verbessert. -Ein Programmierstil legt unter anderem Regeln und Richtlinien für nachfolgende -Aspekte fest: +Ein Programmierstil legt unter anderem Regeln für folgende Aspekte fest: - Namenskonventionen - Klammersetzung @@ -87,11 +83,11 @@ Zu den bekanntesten Programmierstilen in Java gehören die offiziellen [Code Conventions for the Java Programming Language](https://www.oracle.com/java/technologies/javase/codeconventions-introduction.html) von Oracle sowie der [Google Java Style](https://google.github.io/styleguide/javaguide.html) von -Google. Zudem existiert mit +Google. Zudem gibt es mit [Prettier Java](https://github.com/jhipster/prettier-java) eine Erweiterung für -den weit verbreiteten Code Formatierer [Prettier](https://prettier.io/). Neben -vielen Gemeinsamkeiten wie dem Verzicht auf Tabulatorspürunge zur Einrückung, -den Regeln zu Leerzeichen sowie zur Klammersetzung unterscheiden sich die -genannten Programmierstile aber auch in Regeln wie der Anzahl der Leerzeichen -zur Einrückung, der festgelegten Zeilenlänge sowie dem Umgang mit -Zeilenumbrüchen bei funktionalen Aufrufen. +den weit verbreiteten Code-Formatierer [Prettier](https://prettier.io/). Neben +vielen Gemeinsamkeiten — etwa dem Verzicht auf Tabulatorzeichen zur Einrückung, +den Regeln zu Leerzeichen sowie zur Klammersetzung — unterscheiden sich die +genannten Stile in Details wie der Anzahl der Leerzeichen zur Einrückung, der +festgelegten Zeilenlänge sowie dem Umgang mit Zeilenumbrüchen bei funktionalen +Aufrufen. diff --git a/docs/documentation/javafx.mdx b/docs/documentation/javafx.mdx index 605587c316..570e92f851 100644 --- a/docs/documentation/javafx.mdx +++ b/docs/documentation/javafx.mdx @@ -8,18 +8,13 @@ tags: [gui, javafx] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Java stellt mit dem _AWT_ (Abstract Window Toolkit) und _Swing_ zwei -Bibliotheken zur Entwicklung grafischer Benutzeroberflächen zur Verfügung. Swing -baut dabei auf dem älteren AWT auf und verwendet teilweise Klasse daraus. Der -Nachfolger von Swing heißt JavaFX und stellt im Gegensatz zu AWT und Swing keine -Bibliothek, sondern ein Framework zur Entwicklung plattformübergreifender -grafischer Benutzeroberflächen dar. Unter einem Framework versteht man ein -Programmiergerüst, welches die Architektur für die Anwendung vorgibt und den -Kontrollfluss der Anwendung steuert. So werden die Funktionen einer Anwendung -beim Framework registriert, welches die Funktionen zu einem späteren Zeitpunkt -aufruft, d.h. die Steuerung des Kontrollfluss obliegt nicht der Anwendung, -sondern dem Framework. Diese Umkehr der Steuerung kann auch als Anwendung des -Hollywood-Prinzips (_Don´t call us, we´ll call you_) verstanden werden. +Java bietet mit _AWT_ (Abstract Window Toolkit) und _Swing_ zwei ältere +Bibliotheken für grafische Benutzeroberflächen. Der Nachfolger beider ist +_JavaFX_ — ein Framework für plattformübergreifende GUIs. Als Framework gibt +JavaFX die Architektur vor und steuert den Kontrollfluss nach dem Prinzip der +_Inversion of Control_: Statt dass die Anwendung JavaFX aufruft, registriert sie +ihre Funktionen beim Framework, das sie dann aufruft — das sogenannte +Hollywood-Prinzip: _Don't call us, we'll call you_. :::info @@ -30,11 +25,10 @@ eigenständiges SDK (Software Development Kit) dar. ## Aufbau und Lebenszyklus von JavaFX-Anwendungen -JavaFX-Anwendungen bestehen aus einer oder mehreren Bühnen (Stages), die -beliebig vielen Szenen (Scenes) enthalten können, wobei jede Szene wiederum -beliebig viele Bildschirmelemente (Nodes) enthalten kann. Jede JavaFX-Anwendung -ist eine Unterklasse der Klasse `Application`. Diese stellt die verschiedenen -Lebenszyklus-Methoden der JavaFX-Anwendung bereit. +Eine JavaFX-Anwendung besteht aus Bühnen (Stages), die Szenen (Scenes) +enthalten, die wiederum Bildschirmelemente (Nodes) beinhalten. Jede +JavaFX-Anwendung erbt von der Klasse `Application`, die den Lebenszyklus +verwaltet: - Die Methode `void launch(args: String[])` speichert die Aufrufparameter, erzeugt ein Objekt der eigenen Klasse und ruft die weiteren @@ -48,14 +42,12 @@ Lebenszyklus-Methoden der JavaFX-Anwendung bereit. ## Definition von Szenen -Die Definition einer Szene (View) kann entweder objektorientiert oder deklarativ -mit Hilfe von FXML-Dokumenten erfolgen. FXML stellt eine auf XML-basierende -Sprache dar und ermöglicht eine klare Trennung zwischen Layout und Code. XML -(Extensible Markup Language) wiederum stellt eine Auszeichnungssprache zur -Beschreibung strukturierter Daten dar. +Eine Szene (View) kann objektorientiert im Code oder deklarativ mit +FXML-Dokumenten definiert werden. FXML ist eine XML-basierte +Beschreibungssprache, die eine klare Trennung zwischen Layout und Code +ermöglicht. -Mit Hilfe spezifischer JavaFX-Eigenschaften wird eine Verbindung zwischen der -Szene und der Ereignisbehandler-Klasse hergestellt: +JavaFX-spezifische Eigenschaften verknüpfen Szene und Controller: - Bildschirmelementen können über die Eigenschaft `fx:id` IDs zugewiesen werden, über die die Ereignisbehandler-Klasse auf die jeweiligen Elemente zugreifen @@ -115,14 +107,10 @@ Szene und der Ereignisbehandler-Klasse hergestellt: ## Aufruf von Szenen -Die statische Methode `Parent load(location: URL)` der Klasse `FXMLLoader` -überführt das angegebene FXML-Dokument in einen Szenegraphen und gibt den -dazugehörigen Wurzelknoten vom Typ `Parent` zurück, mit dessen Hilfe -anschließend die Szene erstellt und angezeigt werden kann. Zusätzlich -instanziiert der FXML-Loader den Controller und ruft bei der Anzeige der Szene -die (optionale) Methode -`void initialize(location: URL, resources: ResourceBundle)` der entsprechenden -Ereignisbehandler-Klasse auf. +Die Methode `Parent load(location: URL)` der Klasse `FXMLLoader` lädt ein +FXML-Dokument, erstellt den Szenegraphen und gibt den Wurzelknoten zurück. Der +FXML-Loader instanziiert dabei automatisch den Controller und ruft bei Anzeige +der Szene dessen `initialize()`-Methode auf. ```java title="MainClass.java" showLineNumbers public class MainClass extends Application { @@ -145,20 +133,14 @@ public class MainClass extends Application { ## Implementierung von Ereignisbehandler-Klassen -In den Ereignisbehandler-Klassen (Controller) werden die Behandlermethoden -implementiert. Diese müssen zwingend einen Parameter vom Typ des Ereignisses -besitzen (z.B. `ActionEvent`), mit dessen Hilfe auf das ausgelöste Ereignis -zugegriffen werden kann. Das Verknüpfen von Attributen der -Ereignisbehandler-Klasse mit den Elementen des FXML-Dokuments erfolgt über die -Annotation `@FXML` und der Namensgleichheit zwischen den Attributen der -Ereignisbehandler-Klasse sowie den festgelegten Ids der entsprechenden Elemente -des FXML-Dokuments. - -Der Wechsel von Szenen erfolgt über die Methode `void setScene(value: Scene)` -der Klasse `Window`. Die Methode `Object getSource()` der Klasse `ActionEvent` -gibt das Bildschirmelement zurück, welches das Ereignis ausgelöst hat; die -Methode `Window getWindow()` der Klasse `Scene` die Bühne, auf der die aktuelle -Szene aufgeführt wird. +In den Controller-Klassen werden die Behandlermethoden implementiert. Jede +Behandlermethode muss einen Parameter vom Typ des Ereignisses besitzen (z.B. +`ActionEvent`). Die Verknüpfung von Attributen der Controller-Klasse mit +FXML-Elementen erfolgt über die Annotation `@FXML` und übereinstimmende Namen +zwischen Attributen und `fx:id`-Werten im FXML-Dokument. + +Der Szenenwechsel erfolgt über `void setScene(value: Scene)` der Klasse +`Window`. @@ -225,10 +207,9 @@ Szene aufgerufen und ermöglicht es, die Szene dynamisch anzupassen. ## Implementierung von Model-Klassen -Model-Klassen sind für die zentrale Verwaltung der Daten zuständig. Da die -verschiedenen Klassen einer JavaFX-Anwendung nur lose miteiander gekoppelt sind, -kann über das Entwurfsmuster _Singleton_ sichergestellt werden, dass zur -Model-Klasse genau ein Objekt, das sogenannte Singleton, zur Laufzeit existiert. +Model-Klassen verwalten die Anwendungsdaten zentral. Da die Klassen einer +JavaFX-Anwendung nur lose gekoppelt sind, sorgt das Entwurfsmuster _Singleton_ +dafür, dass zur Laufzeit genau ein Model-Objekt existiert. ```java title="Model.java" showLineNumbers public class Model { diff --git a/docs/documentation/lambdas.md b/docs/documentation/lambdas.md index 89f6d73232..d2a66aee60 100644 --- a/docs/documentation/lambdas.md +++ b/docs/documentation/lambdas.md @@ -5,13 +5,13 @@ sidebar_position: 265 tags: [inner-classes, lambdas] --- -Lambda-Ausdrücke sind anonyme Funktionen, die nur über ihre Referenz -angesprochen werden können. +Lambda-Ausdrücke sind anonyme Funktionen, die einer Variablen zugewiesen oder +direkt als Parameter übergeben werden können. ## Implementierung von Lambda-Ausdrücken -Die Methodenparameter sowie der Methodenkörper werden bei einem Lambda-Ausdruck -getrennt vom Pfeiloperator `->` notiert. +Die Parameterliste und der Methodenkörper eines Lambda-Ausdrucks werden durch +den Pfeiloperator `->` getrennt. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -31,29 +31,28 @@ public class MainClass { :::info -Voraussetzung für den Einsatz eines Lambda-Ausdrucks ist eine funktionale -Schnittstelle, also eine Schnittstelle, die über genau eine Methode verfügt. +Voraussetzung für Lambda-Ausdrücke ist eine _funktionale Schnittstelle_ — eine +Schnittstelle mit genau einer abstrakten Methode. ::: ## Syntaxvarianten -- Bei keinem oder mehreren Methodenparametern müssen diese in runden Klammern - angegeben werden, bei genau einem Methodenparameter können die runden Klammern - weggelassen werden -- Besteht der Methodenkörper aus mehreren Anweisungen, müssen diese in - geschweiften Klammern angegeben werden, bei genau einer Anweisung können die - geschweiften Klammern weggelassen werden -- Besteht der Methodenkörper aus genau einer Anweisung, kann das Semikolon am - Anweisungsende weggelassen werden, ist die Anweisung eine return-Anweisung, - kann auch das `return` weggelassen werden +Die Syntax von Lambda-Ausdrücken erlaubt verschiedene Kurzformen: + +- Enthält die Parameterliste genau einen Parameter, können die runden Klammern + weggelassen werden; bei keinem oder mehreren Parametern sind sie verpflichtend +- Besteht der Methodenkörper aus genau einer Anweisung, können die geschweiften + Klammern und das abschließende Semikolon weggelassen werden +- Besteht diese eine Anweisung aus einer `return`-Anweisung, kann auch das + Schlüsselwort `return` weggelassen werden ## Methodenreferenzen -Lambda-Ausdrücke, die nur aus dem Aufruf einer Methode bestehen, können als -Methodenreferenz dargestellt werden. Bei einer Methodenreferenz wird die Klasse -bzw. die Referenz auf der linken Seite mit Hilfe zweier Doppelpunkte vom -Methodennamen auf der recht Seite getrennt. +Besteht ein Lambda-Ausdruck ausschließlich aus dem Aufruf einer Methode, kann er +als _Methodenreferenz_ geschrieben werden. Die Klasse oder Referenz auf der +linken Seite wird dabei durch `::` vom Methodennamen auf der rechten Seite +getrennt. ```java title="MainClass.java" showLineNumbers public class MainClass { diff --git a/docs/documentation/lists.mdx b/docs/documentation/lists.mdx index 7d0701cc1d..4baef83eb0 100644 --- a/docs/documentation/lists.mdx +++ b/docs/documentation/lists.mdx @@ -2,24 +2,23 @@ title: Listen description: '' sidebar_position: 215 -tags: [collections, namess] +tags: [collections, lists] --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Die Java API stellt unter Anderem die Schnittstelle `List` sowie die Klassen -`ArrayList`, `LinkedList` und `Arrays` zur Verfügung, mit deren Hilfe -Listen realisiert werden. Unter einer Liste versteht man eine geordnete Folge -von Elementen, die auch doppelt enthalten sein können. Der Zugriff auf die -Elemente erfolgt über den Index oder sequentiell. +Eine Liste ist eine geordnete Folge von Elementen, die auch doppelte Einträge +enthalten kann. Der Zugriff erfolgt über den Index oder sequentiell. Die Java +API stellt dafür die Schnittstelle `List` sowie die Klassen `ArrayList`, +`LinkedList` und `Arrays` bereit. -Die Schnittstelle `List` bietet verschiedene Fabrikmethoden zum Erzeugen -unveränderbarer Listen. Unveränderbar bedeutet, dass weder die Liste selbst noch -ihre Elemente geändert werden können. +Die Schnittstelle `List` bietet Fabrikmethoden zum Erzeugen unveränderlicher +Listen. Unveränderbar bedeutet, dass weder Elemente hinzugefügt, entfernt noch +ersetzt werden können. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -29,9 +28,9 @@ public class MainClass { System.out.println(names.size()); System.out.println(names.get(0)); - names.set(0, "Max"); // Laufzeitfehler - names.add("Heidi"); // Laufzeitfehler - names.remove(0); // Laufzeitfehler + names.set(0, "Max"); // Laufzeitfehler: Liste ist unveränderbar + names.add("Heidi"); // Laufzeitfehler: Liste ist unveränderbar + names.remove(0); // Laufzeitfehler: Liste ist unveränderbar } } @@ -46,9 +45,10 @@ Fabrikmethoden sind Methoden, die Objekte erzeugen. -Die Klasse `Arrays` stellt neben Methoden zum Sortieren und Durchsuchen von -Feldern auch eine Methode zum Erzeugen veränderbarer Listen fixer Größe zur -Verfügung. +Die Klasse `Arrays` bietet neben Methoden zum Sortieren und Durchsuchen von +Feldern auch eine Methode zum Erzeugen veränderbarer Listen fixer Größe. Die +Anzahl der Elemente ist dabei festgelegt; einzelne Elemente lassen sich jedoch +ersetzen. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -58,9 +58,9 @@ public class MainClass { System.out.println(names.size()); System.out.println(names.get(0)); - names.set(0, "Max"); - names.add("Heidi"); // Laufzeitfehler - names.remove(0); // Laufzeitfehler + names.set(0, "Max"); // Element ersetzen ist erlaubt + names.add("Heidi"); // Laufzeitfehler: Größe ist fest + names.remove(0); // Laufzeitfehler: Größe ist fest } } @@ -69,15 +69,16 @@ public class MainClass { -Die Klasse `ArrayList` stellt eine veränderbare Liste dynamischer Größe auf -Basis eine Feldes dar, die Klasse `LinkedList` eine veränderbare Liste -dynamischer Größe auf Basis doppelt verketteter Elemente. +Die Klasse `ArrayList` implementiert eine veränderbare Liste auf Basis eines +Feldes, die Klasse `LinkedList` auf Basis doppelt verketteter Knoten. Beide +unterstützen das Hinzufügen, Ersetzen und Entfernen von Elementen sowie eine +dynamische Größe. ```java title="MainClass.java" showLineNumbers public class MainClass { public static void main(String[] args) { - List names = new ArrayList<>(); // = new LinkedList<>(); + List names = new ArrayList<>(); // alternativ: new LinkedList<>() names.add("Hans"); names.add("Peter"); names.add("Lisa"); @@ -94,9 +95,10 @@ public class MainClass { :::info -Eine feldbasierte Liste ist bei wahlfreiem Zugriff schneller als eine verkettete -Liste; eine verkettete Liste ist bei Anfüge- und Löschoperationen (insbesondere -bei großen Elementzahlen) schneller als eine feldbasierte Liste. +Eine feldbasierte Liste (`ArrayList`) ist bei wahlfreiem Zugriff über den Index +schneller. Eine verkettete Liste (`LinkedList`) ist bei Einfüge- und +Löschoperationen in der Mitte der Liste schneller, da keine Elemente verschoben +werden müssen. ::: diff --git a/docs/documentation/lombok.mdx b/docs/documentation/lombok.mdx index ddf8439317..23268630b7 100644 --- a/docs/documentation/lombok.mdx +++ b/docs/documentation/lombok.mdx @@ -8,15 +8,14 @@ tags: [lombok] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -[Lombok](https://projectlombok.org/) stellt eine externe Java-Bibliothek dar, -die das Erstellen von Boilerplate-Code überflüssig macht. Repetitive Methoden -wie Konstruktoren, Getter, Setter und die Objekt-Methoden müssen nicht manuell -implementiert werden, sondern werden beim Kompilieren generiert. +[Lombok](https://projectlombok.org/) ist eine externe Java-Bibliothek, die +wiederkehrenden Boilerplate-Code automatisch generiert. Konstruktoren, Getter, +Setter und die `Object`-Methoden werden nicht manuell geschrieben, sondern beim +Kompilieren durch Annotationen erzeugt. ## Annotationen -Durch entsprechende Annotationen kann gesteuert werden, welche Methoden wie -generiert werden sollen. +Über Annotationen wird gesteuert, welche Methoden Lombok generieren soll. | Annotation | Beschreibung | | -------------------------- | -------------------------------------------------------------------------------------------------- | @@ -30,8 +29,9 @@ generiert werden sollen. ## Beispiel -Für die Klasse `Student` werden mit Hilfe von Lombok-Annotationen Konstruktoren, -Setter und Getter sowie die Object-Methoden generiert. +Die Klasse `Student` wird mit Lombok-Annotationen versehen, sodass +Konstruktoren, Getter, Setter und die `Object`-Methoden automatisch generiert +werden. diff --git a/docs/documentation/loops.md b/docs/documentation/loops.md index 7a8964620d..522caf823c 100644 --- a/docs/documentation/loops.md +++ b/docs/documentation/loops.md @@ -5,16 +5,15 @@ sidebar_position: 105 tags: [control-structures, loops] --- -Schleifen sind eine von zwei Möglichkeiten, Anweisungsblöcke wiederholt -auszuführen. Die zweite Möglichkeit sind Selbstaufrufe in Form rekursiver -Methoden. +Schleifen sind eine Möglichkeit, Anweisungsblöcke wiederholt auszuführen. Eine +weitere Möglichkeit sind rekursive Methoden, die sich selbst aufrufen. ## while-Schleifen -Bei der while-Schleife wird eine bestimmte Anweisungsfolge (_Schleifenrumpf_) -wiederholt, solange eine bestimmte Bedingung (_Schleifenbedingung_) wahr ist. Da -zu Beginn der Schleife die Bedingung geprüft wird, spricht man auch von einer -_kopfgesteuerten Schleife_. +Bei der while-Schleife wird ein Anweisungsblock (_Schleifenrumpf_) wiederholt, +solange eine Bedingung (_Schleifenbedingung_) wahr ist. Da die Bedingung zu +Beginn jedes Durchlaufs geprüft wird, spricht man von einer _kopfgesteuerten +Schleife_. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -33,8 +32,8 @@ public class MainClass { ## do/while-Schleifen Im Gegensatz zur while-Schleife wird bei der do/while-Schleife der -Schleifenrumpf immer mindestens einmal durchlaufen. Da die Bedingung hier am -Ende der Schleife geprüft wird, spricht man hier von einer _fußgesteuerten +Schleifenrumpf immer mindestens einmal ausgeführt, da die Bedingung erst am Ende +des Durchlaufs geprüft wird. Daher spricht man von einer _fußgesteuerten Schleife_. ```java title="MainClass.java" showLineNumbers @@ -53,9 +52,8 @@ public class MainClass { ## for-Schleifen -Bei der for-Schleife handelt es sich um eine indexgesteuerte Schleife, auch -_Zählschleife_ genannt. Durch den Index wird bereits zu Schleifenbeginn -festgelegt, wie oft die Schleife durchlaufen wird. +Die for-Schleife ist eine indexgesteuerte Schleife, auch _Zählschleife_ genannt. +Der Index legt bereits zu Beginn fest, wie oft die Schleife durchlaufen wird. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -71,10 +69,10 @@ public class MainClass { ## for-each-Schleifen -Mit Hilfe der for-each-Schleife können Datensammlungen wie z.B. [Felder](arrays) -und [Listen](lists) elementweise durchlaufen werden. Allerdings können die -Elemente einer Datensammlung nur geändert werden, nicht jedoch die Datensammlung -selbst. +Mit der for-each-Schleife können Datensammlungen wie [Felder](arrays) und +[Listen](lists) elementweise durchlaufen werden. Dabei können einzelne Elemente +verändert werden, jedoch nicht die Struktur der Sammlung selbst (z.B. kein +Hinzufügen oder Entfernen von Elementen). ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -91,10 +89,9 @@ public class MainClass { ## Schleifensteuerung -Die Anweisung `break` sorgt dafür, dass eine Schleife ungeachtet der Bedingung -komplett verlassen wird. Mit der Anweisung `continue` wird der aktuelle -Schleifendurchgang abgebrochen und die Schleife wird mit dem nächsten Durchlauf -fortgeführt. +Mit `break` wird eine Schleife unabhängig von der Bedingung sofort beendet. Mit +`continue` wird der aktuelle Schleifendurchgang abgebrochen und die Schleife mit +dem nächsten Durchlauf fortgesetzt. ```java title="MainClass.java" showLineNumbers public class MainClass { diff --git a/docs/documentation/maps.md b/docs/documentation/maps.md index 3d9bf6a240..641b6664d2 100644 --- a/docs/documentation/maps.md +++ b/docs/documentation/maps.md @@ -5,11 +5,9 @@ sidebar_position: 280 tags: [maps] --- -Unter einem Assoziativspeicher (Map) versteht man eine Menge zusammengehöriger -Paare von Objekten. Das erste Objekt stellt dabei den Schlüssel (Key), das -zweite Objekt den Wert (Value) dar. Jeder Schlüssel kann dabei nur einmal in -einem Assoziativspeicher vorhanden sein. Aufgrund dieses Aufbaus werden -Assoziativspeicher auch als Wörterbücher bezeichnet. +Ein Assoziativspeicher (Map) ist eine Sammlung von Schlüssel-Wert-Paaren. Jeder +Schlüssel (Key) ist eindeutig und verweist auf genau einen Wert (Value). Wegen +dieser Struktur werden Assoziativspeicher auch als _Wörterbücher_ bezeichnet. ```mermaid flowchart LR @@ -22,10 +20,9 @@ flowchart LR end ``` -Um auf die Einträge, Schlüssel und Werte eines Assoziativspeichers zugreifen -können, stellt die Schnittstelle `Map` die Methoden -`Set> entrySet()`, `Set keySet()` und `Collection values()` -zur Verfügung. +Für den Zugriff auf Einträge, Schlüssel und Werte eines Assoziativspeichers +stellt die Schnittstelle `Map` die Methoden `Set> entrySet()`, +`Set keySet()` und `Collection values()` bereit. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -55,12 +52,10 @@ public class MainClass { } ``` -Die Klasse `HashMap` implementiert den Assoziativspeicher in Form einer -Hashtabelle. Für den Einsatz einer Hashtabelle ist es zwingend erforderlich, -dass die Klasse, die den Schlüssel bildet, die Methoden `int hashCode()` und -`boolean equals(object: Object)` gemäß den entsprechenden -Dokumentationskommentaren überschrieben hat. Im Gegensatz zu einem Binärbaum -liegen die Paare in einer Hashtabelle unsortiert vor. +Die Klasse `HashMap` implementiert den Assoziativspeicher als Hashtabelle. +Voraussetzung ist, dass die Schlüsselklasse die Methoden `int hashCode()` und +`boolean equals(object: Object)` korrekt überschrieben hat. Die Einträge liegen +in einer Hashtabelle unsortiert vor. | Index | Schlüssel | Wert | | ----- | --------- | ---- | @@ -69,14 +64,12 @@ liegen die Paare in einer Hashtabelle unsortiert vor. | 13 | Lisa | 1.8 | | 14 | Max | 4.2 | -Die Klasse `TreeMap` implementiert den Assoziativspeicher in Form eines -Binärbaumes. Als Datenstruktur wird dabei ein balancierter Baum verwendet, d.h. -spezielle Einfüge- und Löschoperationen stellen sicher, dass der Baum nicht zu -einer linearen Liste entartet. Da die Paare in einem Binärbaum sortiert -vorliegen, ist es für den Einsatz zwingend erforderlich, dass die Klasse, die -den Schlüssel bildet, die Schnittstelle `Comparable` implementiert hat. -Alternativ kann dem Konstruktor der Klasse `TreeMap` ein Komparator für -den Schlüssel mitgegeben werden. +Die Klasse `TreeMap` implementiert den Assoziativspeicher als Binärbaum. +Dabei wird ein balancierter Baum verwendet, sodass spezielle Einfüge- und +Löschoperationen sicherstellen, dass der Baum nicht zu einer linearen Liste +entartet. Die Einträge liegen sortiert vor, weshalb die Schlüsselklasse die +Schnittstelle `Comparable` implementieren oder dem Konstruktor ein +`Comparator` übergeben werden muss. ```mermaid flowchart TD diff --git a/docs/documentation/mockito.mdx b/docs/documentation/mockito.mdx index 1b36eb37c9..4c8c411ee6 100644 --- a/docs/documentation/mockito.mdx +++ b/docs/documentation/mockito.mdx @@ -8,68 +8,50 @@ tags: [mockito] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -[Mockito](https://site.mockito.org/) ist ein leistungsfähiges und einfach zu -verwendendes Framework für das Erstellen von Mock-Objekten in Java. Mock-Objekte -simulieren das Verhalten realer Komponenten und werden oft in Tests anstelle der -realen Komponenten verwendet. Durch den Einsatz von Mock-Objekten werden die -Abhängigkeiten des SUT (System under Test) minimiert und so das Testen von -Anwendungen erheblich vereinfacht. Man spricht in diesem Zusammenhang auch von -der sogenannten Test-Isolierung. Gründe für den Einsatz von Mock-Objekten können -komplexe Abhängigkeiten, ungewünschte Seiteneffekte oder hohe Laufzeiten der -realen Komponenten sein. +[Mockito](https://site.mockito.org/) ist ein Framework für das Erstellen von +Mock-Objekten in Java. Mock-Objekte simulieren das Verhalten realer Komponenten +und ersetzen diese in Tests. Dadurch werden Abhängigkeiten des SUT (System under +Test) reduziert und die Tests isoliert (Test-Isolierung). Typische Gründe für +Mock-Objekte sind komplexe Abhängigkeiten, unerwünschte Seiteneffekte oder hohe +Laufzeiten realer Komponenten. ## Arten von Mock-Objekten -Man unterscheidet zwischen verschiedenen Arten von Mock-Objekten. +Mockito unterscheidet zwischen drei Arten von Testobjekten: -- Ein _Stub_ ist ein Objekt, welches beim Aufruf einer Methode unabhängig der - Eingabe immer den selben festgelegten Wert zurückgibt -- Ein _Mock_ ist ein Objekt, welches im Gegensatz zum Stub beim Aufruf einer - Methode abhängig von der Eingabe festgelegte Werte zurückgibt -- Ein _Spy_ ist ein Objekt, welches Aufrufe und übergebene Werte protokolliert - und abfragbar macht +- Ein _Stub_ gibt unabhängig von der Eingabe immer denselben festgelegten Wert + zurück. +- Ein _Mock_ gibt abhängig von der Eingabe unterschiedliche festgelegte Werte + zurück. +- Ein _Spy_ protokolliert Methodenaufrufe und die übergebenen Argumente, sodass + sie im Test abgefragt werden können. ## Simulieren von Objekten -Mockito stellt für das Erzeugen von Mock-Objekten zum Einen die statische -Methode `T mock(reified: T...)` der Klasse `Mockito` und zum Anderen die -Annotation `@Mock` sowie die statische Methode -`AutoCloseable openMocks(testClass: Object)` der Klasse `MockitoAnnotations` zur -Verfügung. In beiden Fällen wird ein entsprechendes Objekt der angegebenen -Klasse erstellt, allerdings ohne jegliche Methodenimplementierungen. Das -Verhalten einzelner Methoden kann anschließend über die statische Methode -`OngoingStubbing when(methodCall: T)` der Klasse `Mockito` sowie über die -Methode `OngoingStubbing thenReturn(value: T)` bzw. -`OngoingStubbing thenThrow(throwables: Throwable...)` der Klasse -`OngoingStubbing` festgelegt werden. +Mock-Objekte werden entweder mit der statischen Methode `T mock(reified: T...)` +der Klasse `Mockito` oder mit der Annotation `@Mock` in Verbindung mit +`MockitoAnnotations.openMocks()` erstellt. Ein so erzeugtes Objekt hat keine +Methodenimplementierungen. Das gewünschte Verhalten wird über +`Mockito.when(...).thenReturn(...)` bzw. `.thenThrow(...)` festgelegt. ## Umhüllen von Objekten -Für das Erzeugen von Spy-Objekten stellt Mockito zum Einen die statische Methode -`T spy(object: T)` der Klasse `Mockito` und zum Anderen die Annotation `@Spy` -sowie die statische Methode `AutoCloseable openMocks(testClass: Object)` der -Klasse `MockitoAnnotations` zur Verfügung. Durch das so umhüllte Objekt kann das -Verhalten einzelner Methoden anschließend über die statische Methode -`Stubber doReturn(toBeReturned: Object)` bzw. -`Stubber doThrow(toBeThrown: Throwable...)` der Klasse `Mockito` sowie über die -Methode `T when(mock: T)` der Klasse `Stubber` überschrieben werden. +Spy-Objekte werden mit `T spy(object: T)` der Klasse `Mockito` oder mit der +Annotation `@Spy` erstellt. Im Gegensatz zum Mock delegiert ein Spy +standardmäßig an die echte Implementierung. Einzelne Methoden können mit +`Mockito.doReturn(...).when(...)` überschrieben werden. ## Prüfen von Methodenaufrufen -Für das Prüfen, ob, wie oft und in welcher Reihenfolge eine Methode eines -Mock-Objektes aufgerufen wurde, stellt Mockito die statische Methode -`T verify(mock: T, mode: VerificationMode)` der Klasse `Mockito` zur Verfügung. -Zur Angabe des Prüfungsmodus können die statischen Methoden -`VerificationMode times(wantedNumberOfInvocations: int)`, -`VerificationMode atLeast(minNumberOfInvocations: int)`, -`VerificationMode atMost(maxNumberOfInvocations: int)` und -`VerificationMode never()` der Klasse `Mockito` verwendet werden. +Mit `Mockito.verify(mock, mode)` wird geprüft, ob und wie oft eine Methode +aufgerufen wurde. Als Modus stehen u.a. `times(n)`, `atLeast(n)`, `atMost(n)` +und `never()` zur Verfügung. ## Argument Matcher -Die Klasse `ArgumentMatchers` stellt eine Reihe statischer Methoden wie z.B. -`String anyString()` und `List anyList()` zur Verfügung, die ein flexibles -Simulieren von Objekten und Prüfen von Methodenaufrufen ermöglichen. +Die Klasse `ArgumentMatchers` bietet statische Methoden wie `anyString()` oder +`anyList()`, um beim Simulieren und Verifizieren flexible Eingabebedingungen +festzulegen. ## Beispiel diff --git a/docs/documentation/object.md b/docs/documentation/object.md index a618897691..3eae6ce980 100644 --- a/docs/documentation/object.md +++ b/docs/documentation/object.md @@ -5,17 +5,17 @@ sidebar_position: 190 tags: [object] --- -Alle Klassen in Java sind letztlich Unterklassen der Klasse `Object`. Daher wird -diese auch als die Mutter aller Klassen bezeichnet. Die Klasse vererbt ihren +Alle Klassen in Java sind letztlich Unterklassen der Klasse `Object`, die daher +auch als die _Mutter aller Klassen_ bezeichnet wird. Sie vererbt ihren Unterklassen unter anderem die Methoden `boolean equals(object: Object)`, -`int hashCode()` und `String toString()`. Diese drei Methoden sollte jede -Unterklasse sinnvoll überschreiben. +`int hashCode()` und `String toString()`. Diese drei Methoden sollte jede eigene +Klasse sinnvoll überschreiben. ## Die Methode _boolean equals(object: Object)_ -Die Methode `boolean equals(object: Object)` prüft zwei Objekte auf Gleichheit. -Zwei Objekte gelten dabei in der Regel als gleich, wenn all ihre Attribute -gleich sind. +Die Methode `boolean equals(object: Object)` prüft zwei Objekte auf inhaltliche +Gleichheit. Zwei Objekte gelten in der Regel als gleich, wenn alle ihre +Attribute übereinstimmen. ```java title="Computer.java (Auszug)" showLineNumbers public class Computer { @@ -41,10 +41,10 @@ public class Computer { ## Die Methode _int hashCode()_ -Die Methode `int hashCode()` liefert den Hashcode des aktuellen Objektes zurück. -Die Methode sollte so überschrieben werden, dass gleiche Objekte den gleichen -Hashwert zurückgeben. Dies ist vor allem beim Arbeiten mit Hash-basierten -Datensammlungen wie z.B. der Klasse `HashMap` notwendig. +Die Methode `int hashCode()` liefert den Hashcode des aktuellen Objekts zurück. +Sie sollte so überschrieben werden, dass inhaltlich gleiche Objekte denselben +Hashwert liefern. Das ist insbesondere beim Arbeiten mit Hash-basierten +Datensammlungen wie `HashMap` notwendig. ```java title="Computer.java (Auszug)" showLineNumbers public class Computer { @@ -60,19 +60,18 @@ public class Computer { :::info -Die statische Methode `int hash(values: Object...)` der Klasse `Objects` liefert -eine einfache Möglichkeit zur Implementierung der Methode `boolean hashCode()`. +Die statische Methode `int hash(values: Object...)` der Klasse `Objects` bietet +eine einfache Möglichkeit zur Implementierung von `hashCode()`. ::: ## Die Methode _String toString()_ -Die Methode `String toString()` liefert eine eindeutige Kennung des Objektes in -der Form _[Vollständiger Klassenname]_@_[Adresse des Objektes im Hauptspeicher -in hexadezimaler Notation]_ zurück. Die Methode sollte so überschrieben werden, -dass alle relevanten Attribute des Objektes als Zeichenkette zurückgegeben -werden. In der Regel geschieht dies in der Form _[Klassenname] -[[Attribut]=[Attributswert], ...]_. +Die Methode `String toString()` liefert eine eindeutige Kennung des Objekts in +der Form _[vollständiger Klassenname]_@_[Adresse im Hauptspeicher in +hexadezimaler Notation]_ zurück. Üblicherweise wird sie so überschrieben, dass +alle relevanten Attribute als Zeichenkette zurückgegeben werden — typischerweise +in der Form _[Klassenname][Attribut]=[Wert], ...]_. ```java title="Computer.java" showLineNumbers public class Computer { diff --git a/docs/documentation/oo.md b/docs/documentation/oo.md index 24c170b53b..88b15f2f7d 100644 --- a/docs/documentation/oo.md +++ b/docs/documentation/oo.md @@ -6,24 +6,22 @@ tags: [oo] --- Die reale Welt besteht aus Objekten mit individuellen Eigenschaften und -individuellem Verhalten. Für ein einfacheres Verständnis werden Objekte -kategorisiert, also zu sinnhaften Einheiten verbunden. In der objektorientierten -Programmierung werden Beobachtungen aus der realen Welt zum Konzept der -Objektorientierung zusammengefasst: +individuellem Verhalten. Um diese Komplexität handhabbar zu machen, werden +Objekte kategorisiert und zu sinnvollen Einheiten zusammengefasst. Die +objektorientierte Programmierung überträgt dieses Prinzip auf Software: -- Eine Kategorie von ähnlichen Objekten bezeichnet man als _Klasse_ -- Konkrete Ausprägungen bzw. Instanzen einer Klasse werden wiederum als - _Objekte_ bezeichnet -- Die Eigenschaften von Objekten werden als _Attribute_ das Verhalten als +- Eine Kategorie ähnlicher Objekte bezeichnet man als _Klasse_ +- Konkrete Ausprägungen einer Klasse nennt man _Objekte_ (auch _Instanzen_) +- Die Eigenschaften von Objekten werden als _Attribute_, ihr Verhalten als _Methoden_ bezeichnet ## Datenkapselung Ein wesentlicher Grundsatz der Objektorientierung ist, dass Attribute durch -Methoden gekapselt werden. Datenkapselung bedeutet, dass auf Attribute nicht +Methoden gekapselt werden. _Datenkapselung_ bedeutet, dass auf Attribute nicht direkt zugegriffen werden kann, sondern nur indirekt über Methoden. Typische -Methoden zum Lesen und Schreiben von Attributen sind die sogenannten Getter bzw. -Setter (auch Set- und Get-Methoden bzw. Accessors genannt). +Methoden zum Lesen und Schreiben von Attributen sind Getter bzw. Setter (auch +Accessors und Mutators genannt). ```mermaid flowchart LR @@ -44,13 +42,12 @@ flowchart LR ## Abstraktion -Abstraktion bedeutet das Zerlegen von komplexen Systeme in kleinere, -überschaubare Einheiten, indem der Fokus auf die wesentlichen Eigenschaften und -das wesentliche Verhalten gesetzt und unwichtige Details ausgeblendet werden. -Dies bringt einige Vorteile wie bessere Wiederverwendbarkeit, bessere -Wartbarkeit sowie bessere Lesbarkeit mit sich. In der Objektorientierten -Programmierung erfolgt die Abstraktion durch den Einsatz von (abstrakten) -Klassen bzw. Schnittstellen (Interfaces). +_Abstraktion_ bedeutet, komplexe Systeme in kleinere, überschaubare Einheiten zu +zerlegen — indem der Fokus auf die wesentlichen Eigenschaften und das +wesentliche Verhalten gelegt und unwichtige Details ausgeblendet werden. Das +bringt Vorteile wie bessere Wiederverwendbarkeit, Wartbarkeit und Lesbarkeit. In +Java wird Abstraktion durch den Einsatz von (abstrakten) Klassen und +Schnittstellen (Interfaces) realisiert. ```mermaid flowchart LR diff --git a/docs/documentation/operators.mdx b/docs/documentation/operators.mdx index aa614fdc88..5b05ba0a1f 100644 --- a/docs/documentation/operators.mdx +++ b/docs/documentation/operators.mdx @@ -9,17 +9,16 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; Operatoren sind Zeichen, mit denen Daten manipuliert werden können. Mit Hilfe -von Operanden und Operatoren können beliebig komplexe Ausdrücke abgebildet -werden. Operatoren mit einem, zwei oder drei Operanden werden als _unäre -Operatoren_ _binäre Operatoren_ und _ternäre Operatoren_ bezeichnet. Man -unterscheidet zudem zwischen arithmetischen, bitweisen und logischen Operatoren -sowie Vergleichsoperatoren. +von Operanden und Operatoren lassen sich beliebig komplexe Ausdrücke aufbauen. +Operatoren mit einem, zwei oder drei Operanden werden als _unäre_, _binäre_ bzw. +_ternäre_ Operatoren bezeichnet. Man unterscheidet zwischen arithmetischen, +bitweisen und logischen Operatoren sowie Vergleichsoperatoren. -Für die arithmetischen Grundrechenarten stehen verschiedene arithmetische -Operatoren zur Verfügung. +Für die arithmetischen Grundrechenarten stehen folgende Operatoren zur +Verfügung. | Ausdruck mit Operator | Bedeutung | | --------------------- | ------------------------------------------------------------- | @@ -36,8 +35,8 @@ Operatoren zur Verfügung. -Bitweise Operatoren können dazu verwendet werden, Binäroperationen auf Operanden -durchzuführen. +Bitweise Operatoren führen Operationen direkt auf den einzelnen Bits der +Operanden durch. | Ausdruck mit Operator | Bedeutung | | --------------------- | ------------------------ | @@ -49,8 +48,8 @@ durchzuführen. -Logische Operatoren können dazu verwendet werden, logische Aussagen miteinander -zu verknüpfen. +Logische Operatoren verknüpfen logische Aussagen miteinander und liefern einen +booleschen Wert zurück. | Ausdruck mit Operator | Bedeutung | | --------------------- | ------------------------ | @@ -61,8 +60,8 @@ zu verknüpfen. -Logische Bedingungen für zwei Werte eines elementaren Datentyps können durch -Vergleichsoperatoren realisiert werden. +Vergleichsoperatoren prüfen logische Bedingungen für zwei Werte eines +elementaren Datentyps und liefern einen booleschen Wert zurück. | Ausdruck mit Operator | Bedeutung | | --------------------- | ---------------------- | @@ -76,8 +75,8 @@ Vergleichsoperatoren realisiert werden. :::info Da der Vergleichsoperator `==` auf referenzielle Gleichheit prüft, sollte zum -Vergleich von zwei Objekten die Methode `boolean equals(object: Object)` -verwendet werden. +inhaltlichen Vergleich von zwei Objekten die Methode +`boolean equals(object: Object)` verwendet werden. ::: @@ -86,7 +85,8 @@ verwendet werden. ## Priorität von Operatoren -Die Verarbeitung von Operatoren erfolgt gemäß ihrer Priorität. +Die Auswertung von Ausdrücken mit mehreren Operatoren erfolgt gemäß ihrer +Priorität. Operatoren mit höherer Priorität werden zuerst ausgewertet. | Priorität | Operator | | --------- | ------------------------------------------------------------ | diff --git a/docs/documentation/optionals.md b/docs/documentation/optionals.md index cc209becf8..0fc42c520f 100644 --- a/docs/documentation/optionals.md +++ b/docs/documentation/optionals.md @@ -5,10 +5,9 @@ sidebar_position: 290 tags: [optionals] --- -Der Umgang mit null-Werten stellt in vielen Programmiersprachen eine große -Herausforderung dar. Zur Vermeidung von Laufzeitfehlern (`NullPointerException`) -müsste vor jedem Methodenaufruf eigentlich überprüft werden, ob ein gültiger -Wert vorliegt oder nicht. +Der Umgang mit `null`-Werten ist in vielen Programmen eine häufige Fehlerquelle. +Ohne explizite Prüfungen kann der Zugriff auf ein `null`-Objekt eine +`NullPointerException` auslösen. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -18,7 +17,7 @@ public class MainClass { public static void main(String[] args) { names = new ArrayList<>(); String name = getNameByInitial('H'); - System.out.println(name.length()); // Laufzeitfehler + System.out.println(name.length()); // Laufzeitfehler: name ist null } public static String getNameByInitial(char initial) { @@ -35,16 +34,14 @@ public class MainClass { } ``` -Die Klasse `Optional` ermöglicht in Java eine komfortable Möglichkeit, mit -null-Werten umzugehen. Das eigentliche Objekt wird dabei in einem Objekt der -Klasse `Optional` verpackt; der Zugriff auf das verpackte Objekt erfolgt über -entsprechende Methoden. Dies stellt sicher, dass sich der Entwickler mit -null-Werten auseinander setzen muss. +Die Klasse `Optional` bietet eine komfortable Möglichkeit, mit `null`-Werten +umzugehen. Das eigentliche Objekt wird in einem `Optional`-Objekt verpackt; der +Zugriff erfolgt über entsprechende Methoden. So wird sichergestellt, dass der +`null`-Fall explizit behandelt werden muss. -Für den Umgang mit null-Werten stellt die Klasse `Optional` Methoden wie -`T get()`, `boolean isPresent()` und `void ifPresent(consumer: Consumer)` zur -Verfügung. Zudem existieren Methoden wie `void orElse(other: T)`, mit denen -Standardwerte festgelegt werden können. +Die Klasse `Optional` stellt u.a. folgende Methoden bereit: `T get()`, +`boolean isPresent()`, `void ifPresent(consumer: Consumer)` und +`T orElse(other: T)` zum Festlegen eines Standardwerts. ```java title="MainClass.java" showLineNumbers public class MainClass { diff --git a/docs/documentation/polymorphism.mdx b/docs/documentation/polymorphism.mdx index 31bc17c23c..500fd2a7f6 100644 --- a/docs/documentation/polymorphism.mdx +++ b/docs/documentation/polymorphism.mdx @@ -8,17 +8,15 @@ tags: [oo, polymorphism] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Unter (dynamischer) Polymorphie (griechisch für Vielgestaltigkeit) versteht man, -dass eine Referenzvariable zur Laufzeit durch Typumwandlung Referenzen auf -Objekte unterschiedlicher Klassen besitzen kann und dass dadurch -unterschiedliche Methodenimplementierungen aufgerufen werden können. Man spricht -in diesem Zusammenhang auch vom _statischen Datentyp einer Referenzvariablen_ -(der zur Designzeit festgelegt wird) und vom _dynamischen Datentyp einer -Referenzvariablen_ (der zur Laufzeit zugewiesen wird). Der statische Typ legt -fest, welche Methoden aufgerufen werden können, der dynamische, welche -Methodenimplementierung aufgerufen wird. Die Typumwandlung von der abgeleiteten -Unterklasse zur Oberklasse bezeichnet man als _Upcast_, die Rückumwandlung als -_Downcast_. +Unter _(dynamischer) Polymorphie_ (griechisch für „Vielgestaltigkeit") versteht +man, dass eine Referenzvariable zur Laufzeit Referenzen auf Objekte +unterschiedlicher Klassen halten kann und dadurch unterschiedliche +Methodenimplementierungen aufgerufen werden. Man unterscheidet dabei zwischen +dem _statischen Datentyp_ (zur Designzeit festgelegt) und dem _dynamischen +Datentyp_ (zur Laufzeit zugewiesen). Der statische Typ bestimmt, welche Methoden +aufrufbar sind; der dynamische Typ bestimmt, welche Implementierung tatsächlich +ausgeführt wird. Die Typumwandlung von der Unterklasse zur Oberklasse nennt man +_Upcast_, die Rückumwandlung _Downcast_. @@ -106,12 +104,10 @@ werden. Der Downcast einer nicht zuweisungskompatiblen Referenz führt zu einer ## Der instanceof-Operator -Mit dem Operator `instanceof` kann zur Laufzeit geprüft werden, ob eine -Objektreferenz zuweisungskompatibel zu einer Klasse ist. Eine Objektreferenz ist -dann zuweisungskompatibel zu einer Klasse, wenn die Klasse des referenzierten -Objektes in einer Vererbungsbeziehung zur Klasse steht. Seit Java 16 ermöglicht -der Mustervergleich bei `instanceof` das Vermeiden notwendiger Typumwandlungen -und sorgt gleichzeitig für eine sicherere Programmierung. +Mit dem Operator `instanceof` lässt sich zur Laufzeit prüfen, ob eine +Objektreferenz mit einer bestimmten Klasse zuweisungskompatibel ist. Seit Java +16 ermöglicht der Mustervergleich (_Pattern Matching_) bei `instanceof` das +direkte Binden in eine neue Variable ohne expliziten Downcast. ```java title="MainClass.java (Auszug)" showLineNumbers public class MainClass { @@ -119,13 +115,13 @@ public class MainClass { public static void main(String[] args) { ... for (Computer c : computers) { - /* bis Java 16 */ + // bis Java 16: expliziter Downcast erforderlich if (c instanceof Notebook) { - Notebook notebook = (Notebook) c; // Downcast + Notebook notebook = (Notebook) c; System.out.println(notebook.getScreenSizeInInches()); } - /* seit Java 16 */ - if (c instanceof Notebook notebook) { // Downcast + // seit Java 16: Pattern Matching + if (c instanceof Notebook notebook) { System.out.println(notebook.getScreenSizeInInches()); } } diff --git a/docs/documentation/pseudo-random-numbers.md b/docs/documentation/pseudo-random-numbers.md index 15037d9b39..ecc479cf89 100644 --- a/docs/documentation/pseudo-random-numbers.md +++ b/docs/documentation/pseudo-random-numbers.md @@ -5,9 +5,11 @@ sidebar_position: 80 tags: [java-api, random] --- -Die Klasse `Random` ermöglicht das Erzeugen von Pseudozufallszahlen. -Pseudozufallszahlen sind scheinbar zufällige Zahlen, die aber auf Grund einer -Formel berechnet werden. +Die Klasse `Random` aus dem Paket `java.util` ermöglicht das Erzeugen von +Pseudozufallszahlen. Als _pseudozufällig_ bezeichnet man Zahlen, die zwar +zufällig wirken, aber durch einen deterministischen Algorithmus auf Basis eines +Startwerts (Seed) berechnet werden. Wird kein Seed angegeben, verwendet Java die +aktuelle Systemzeit. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -16,6 +18,7 @@ public class MainClass { Random random = new Random(); int randomNumber; + // 100 Zufallszahlen von 1 bis 100 ausgeben for (int i = 0; i < 100; i++) { randomNumber = random.nextInt(100) + 1; System.out.println(randomNumber); @@ -24,3 +27,19 @@ public class MainClass { } ``` + +Die folgende Tabelle zeigt häufig verwendete Methoden der Klasse `Random`. + +| Methode | Rückgabetyp | Beschreibung | +| --------------------- | ----------- | --------------------------------------------------------------- | +| `nextInt()` | `int` | Gibt eine zufällige `int`-Zahl zurück | +| `nextInt(bound: int)` | `int` | Gibt eine zufällige `int`-Zahl im Bereich 0 bis bound−1 zurück | +| `nextDouble()` | `double` | Gibt eine zufällige `double`-Zahl im Bereich 0.0 bis 1.0 zurück | +| `nextBoolean()` | `boolean` | Gibt zufällig `true` oder `false` zurück | + +:::info + +Mit `random.nextInt(n) + 1` lassen sich gleichverteilte Zufallszahlen im Bereich +1 bis n erzeugen. + +::: diff --git a/docs/documentation/records.md b/docs/documentation/records.md index 80421e4fd0..ca8d9da484 100644 --- a/docs/documentation/records.md +++ b/docs/documentation/records.md @@ -5,10 +5,10 @@ sidebar_position: 250 tags: [records] --- -Datenklassen sind Klassen die lediglich der Kapselung unveränderlicher Daten -dienen. Daher bestehen Datenklassen häufig aus Boilerplate-Code. Unter -Boilerplate-Code versteht man Anweisungblöcke, die an verschiedenen Stellen mehr -oder weniger identisch verwendet werden. +Datenklassen sind Klassen, die ausschließlich der Kapselung unveränderlicher +Daten dienen. Sie bestehen häufig aus viel _Boilerplate-Code_ — also +Codeabschnitten, die an verschiedenen Stellen nahezu identisch wiederkehren +(Konstruktor, Getter, `equals`, `hashCode`, `toString`). ```java title="Student.java" showLineNumbers public final class Student { @@ -57,11 +57,10 @@ public final class Student { } ``` -Seit Java 16 bieten Records die Möglichkeiten, Datenklassen einfach umzusetzen. -Records sind spezielle Klassen, die anhand der festgelegten Parameter -entsprechende Konstruktoren, Getter sowie Implementierungen für die Methoden -`boolean equals(object: Object)`, `int hashCode()` und `String toString()` -erzeugen. Das Schlüsselwort für Records lautet `record`. +Seit Java 16 bieten _Records_ eine kompakte Möglichkeit, Datenklassen zu +definieren. Ein Record erzeugt anhand der deklarierten Parameter automatisch +einen Konstruktor, Getter sowie Implementierungen für `equals`, `hashCode` und +`toString`. Das Schlüsselwort dafür lautet `record`. ```java title="Student.java" showLineNumbers public record Student(int id, String name) {} diff --git a/docs/documentation/references-and-objects.mdx b/docs/documentation/references-and-objects.mdx index a5c5f573e9..d7adcb56a8 100644 --- a/docs/documentation/references-and-objects.mdx +++ b/docs/documentation/references-and-objects.mdx @@ -8,14 +8,13 @@ tags: [oo] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Technisch gesehen handelt es sich bei einer Klasse um einen komplexen Datentyp. -Analog zu den primitiven Datentypen können auch für Klassen Variablen – -sogenannte _Referenzvariablen_ – definiert werden. +Technisch gesehen ist eine Klasse ein komplexer Datentyp. Analog zu primitiven +Datentypen können für Klassen Variablen — sogenannte _Referenzvariablen_ — +deklariert werden. -Im Gegensatz zu "normalen" Variablen werden bei Referenzvariablen nicht die -eigentlichen Werte in den Variablen gespeichert, sondern die Speicheradressen -der erzeugten Objekte. Die Selbstreferenz `this` verweist innerhalb einer Klasse -auf das eigene Objekt. +Im Gegensatz zu einfachen Variablen speichern Referenzvariablen nicht den Wert +direkt, sondern die Speicheradresse des erzeugten Objekts. Die Selbstreferenz +`this` verweist innerhalb einer Klasse auf das eigene Objekt. ```mermaid flowchart LR @@ -45,14 +44,15 @@ flowchart LR :::info -Der Standarwert von Referenzvariablen ist `null` (auch Nullreferenz genannt). +Der Standardwert von Referenzvariablen ist `null` (auch _Nullreferenz_ genannt). ::: ## Erzeugen von Objekten -Beim Erzeugen eines Objekts mit Hilfe des Operators `new` wird der bei der -Deklaration reservierte Speicherplatz durch das Objekt belegt. +Mit dem `new`-Operator wird ein neues Objekt erzeugt und der zugehörige +Speicherplatz belegt. Nach `new` muss immer ein +[Konstruktor](classes#definition-von-konstruktoren) der Klasse angegeben werden. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -65,20 +65,11 @@ public class MainClass { } ``` -:::info - -Nach dem new-Operator muss immer ein -[Konstruktor](classes#definition-von-konstruktoren) der Klasse stehen. - -::: - ## Zugriff auf Attribute und Aufruf von Methoden -Erlauben die Zugriffsrechte den Zugriff auf ein Attribut bzw. den Aufruf einer -Methode, kann über die deklarierte Referenzvariable und einem nachgestellten -Punkt auf das Attribut zugegriffen bzw. die Methode aufgerufen werden. Der -Zugriff auf statische Attribute bzw. der Aufruf statischer Methoden erfolgt über -den Klassennamen sowie einem nachgestellten Punkt. +Sofern die Zugriffsrechte es erlauben, erfolgt der Zugriff auf ein Attribut oder +der Aufruf einer Methode über die Referenzvariable gefolgt von einem Punkt. +Statische Attribute und Methoden werden über den Klassennamen angesprochen. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -88,7 +79,7 @@ public class MainClass { Computer computer = new Computer("Mein Office PC"); computer.setCpu(cpu); computer.setMemoryInGb(32); - System.out.println(Computer.getNumberOfComputers()); + System.out.println(Computer.getNumberOfComputers()); } } @@ -97,7 +88,6 @@ public class MainClass { :::info Beim Aufruf einer Methode müssen alle Parameter in der richtigen Reihenfolge -versorgt werden. Parameter, die diesem Prinzip folgen, bezeichnet man als -_Positionsparameter_ +übergeben werden. Solche Parameter bezeichnet man als _Positionsparameter_. ::: diff --git a/docs/documentation/slf4j.mdx b/docs/documentation/slf4j.mdx index 7d82e3b721..fd6dbd79b4 100644 --- a/docs/documentation/slf4j.mdx +++ b/docs/documentation/slf4j.mdx @@ -8,19 +8,18 @@ tags: [slf4j] import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -[Simple Logging Facade for Java (SLF4J)](https://www.slf4j.org/) stellt eine -externe Java-Bibliothek dar, die das Protokollieren in Java-Anwendungen -ermöglicht. Protokollierung (Logging) ist ein wesentlicher Bestandteil der -Softwareentwicklung und -wartung und bietet zahlreiche Vorteile wie -Fehlerbehebung, Überwachung, Audit, Compliance, Debugging, Leistungsanalyse -sowie Benutzerunterstützung. Durch die effektive Nutzung von Protokollierung -kann die Zuverlässigkeit, Sicherheit und Leistung einer Anwendung erheblich -verbessert werden. +[Simple Logging Facade for Java (SLF4J)](https://www.slf4j.org/) ist eine +externe Java-Bibliothek für strukturiertes Logging. Logging ist ein zentraler +Bestandteil professioneller Softwareentwicklung und unterstützt bei +Fehlerbehebung, Überwachung, Debugging und Leistungsanalyse. SLF4J ist eine +Abstraktionsschicht (Fassade) und benötigt eine konkrete +Logging-Implementierung, z.B. +[Log4J](https://logging.apache.org/log4j/2.x/index.html). ## Protokollierungs-Level -SLF4J definiert verschiedene Protokollierungs-Level, die die Schwere oder -Wichtigkeit der zu protokollierenden Nachrichten angeben. +SLF4J definiert fünf Protokollierungs-Level, die die Schwere oder Wichtigkeit +einer Nachricht angeben. | Level | Beschreibung | | ----- | ------------------------------------------------------------------------------------------------------------------------ | @@ -32,18 +31,15 @@ Wichtigkeit der zu protokollierenden Nachrichten angeben. ## Protokollierungs-Implementierungen -Die Art der Speicherung von Protokollen in einer Anwendung, die SLF4J verwendet, -hängt von der konkreten Implementierung ab. SLF4J selbst ist dabei nur eine -Fassade und benötigt eine konkrete Implementierung, um die tatsächliche -Protokollierung durchzuführen. Eine der am weitesten verbreiteten -Protokollierungs-Bibliotheken für Java ist -[Log4J](https://logging.apache.org/log4j/2.x/index.html), welches die Ausgabe -von Protokollen auf der Konsole sowie in Protokoll-Dateien ermöglicht. +SLF4J selbst ist nur eine Fassade und führt keine Protokollierung durch. Für die +tatsächliche Ausgabe ist eine konkrete Implementierung nötig. Eine der +gebräuchlichsten ist Log4J, das Protokolle sowohl auf der Konsole als auch in +Dateien ausgeben kann. ## Beispiel -Für die Klasse `MainClass` wird ein Logger initialisiert, mit dessen Hilfe -verschiedene Nachrichten in der Datei _logs/app.log_ protokolliert werden. +Die Klasse `Names` liest Namen aus einer Datei. Ein Logger protokolliert dabei +die wichtigsten Schritte und schreibt die Ausgaben in die Datei _logs/app.log_. diff --git a/docs/documentation/strings.md b/docs/documentation/strings.md index 6a275178e3..683e55f4df 100644 --- a/docs/documentation/strings.md +++ b/docs/documentation/strings.md @@ -5,10 +5,11 @@ sidebar_position: 50 tags: [java-api, strings] --- -Ketten von beliebigen Zeichen werden durch die Klasse `String` realisiert. Diese -stellt einige hilfreiche Methoden zur Verfügung, die bei der Analyse und der -Verarbeitung von Zeichenketten Verwendung finden. Die Angabe einer Zeichenkette -erfolgt über die Anführungszeichen. +Zeichenketten (Strings) sind Folgen beliebiger Zeichen und werden in Java durch +die Klasse `String` realisiert. Sie ist keine primitive, sondern eine +strukturierte Datentyp-Klasse und stellt zahlreiche Methoden zur Analyse und +Verarbeitung von Zeichenketten bereit. Zeichenketten werden in Anführungszeichen +geschrieben. ```java title="MainClass.java" showLineNumbers public class MainClass { @@ -17,34 +18,56 @@ public class MainClass { String text = "Winter"; String text2 = "Coming"; + // Zeichenketten verbinden String text3 = text + " is " + text2; - int length = text3.length(); - char charAt1 = text3.charAt(0); - String upperCase = text3.toUpperCase(); + int length = text3.length(); // Länge der Zeichenkette + char charAt1 = text3.charAt(0); // Zeichen an Position 0 + String upperCase = text3.toUpperCase(); // In Großbuchstaben umwandeln } } ``` +Die folgende Tabelle zeigt häufig verwendete Methoden der Klasse `String`. + +| Methode | Rückgabetyp | Beschreibung | +| ----------------------------------- | ----------- | ----------------------------------------------------------- | +| `length()` | `int` | Gibt die Anzahl der Zeichen zurück | +| `charAt(index: int)` | `char` | Gibt das Zeichen an der angegebenen Position zurück | +| `indexOf(str: String)` | `int` | Gibt die erste Fundstelle der Teilzeichenkette zurück | +| `substring(begin: int)` | `String` | Gibt den Teilstring ab der angegebenen Position zurück | +| `substring(begin: int, end: int)` | `String` | Gibt den Teilstring zwischen begin und end zurück | +| `toUpperCase()` | `String` | Wandelt alle Zeichen in Großbuchstaben um | +| `toLowerCase()` | `String` | Wandelt alle Zeichen in Kleinbuchstaben um | +| `trim()` | `String` | Entfernt führende und abschließende Leerzeichen | +| `replace(old: String, new: String)` | `String` | Ersetzt alle Vorkommen eines Teilstrings durch einen neuen | +| `contains(str: String)` | `boolean` | Prüft, ob die Zeichenkette einen Teilstring enthält | +| `startsWith(prefix: String)` | `boolean` | Prüft, ob die Zeichenkette mit dem Präfix beginnt | +| `endsWith(suffix: String)` | `boolean` | Prüft, ob die Zeichenkette mit dem Suffix endet | +| `equals(other: Object)` | `boolean` | Prüft auf inhaltliche Gleichheit | +| `equalsIgnoreCase(other: String)` | `boolean` | Prüft auf inhaltliche Gleichheit ohne Groß-/Kleinschreibung | +| `split(regex: String)` | `String[]` | Teilt die Zeichenkette anhand eines Trennzeichens auf | + ## Escape-Sequenzen Steuer- und Sonderzeichen in Zeichenketten können mit Hilfe einer Escape-Sequenz -realisiert werden. +eingefügt werden. -| Escape-Squenz | Beschreibung | -| ------------------- | ----------------- | -| \\n | Zeilensprung | -| \\t | Tabulatorsprung | -| \\\\ | Schräger rechts | -| \\" | Anführungszeichen | -| \\' | Hochkomma | -| \\u0000 bis \\uFFFF | Unicode-Zeichen | +| Escape-Sequenz | Beschreibung | +| --------------------- | ----------------- | +| `\n` | Zeilenumbruch | +| `\t` | Tabulatorzeichen | +| `\\` | Backslash | +| `\"` | Anführungszeichen | +| `\'` | Hochkomma | +| `\u0000` bis `\uFFFF` | Unicode-Zeichen | ## Textblöcke Seit Java 15 ermöglichen Textblöcke mehrzeilige Zeichenketten ohne umständliche -Umwege. +Escape-Sequenzen. Der Inhalt wird durch drei Anführungszeichen (`"""`) +eingeschlossen. ```java title="MainClass.java" showLineNumbers public class MainClass { diff --git a/docs/documentation/tests.md b/docs/documentation/tests.md index 9bd8be8552..59f95eceaa 100644 --- a/docs/documentation/tests.md +++ b/docs/documentation/tests.md @@ -5,11 +5,10 @@ sidebar_position: 310 tags: [tests] --- -Softwaretests sollen sicherstellen, dass bei der Entwicklung oder Änderung einer -Software der Quellcode in allen festgelegten Anwendungsfällen korrekt -funktioniert. Mit Hilfe von Softwaretests können Softwareentwickler im Idealfall -schon während des Entwicklungsprozesses mögliche Fehler identifizieren und -beheben. Man unterscheidet dabei zwischen verschiedenen Testarten: +Softwaretests stellen sicher, dass eine Anwendung in allen vorgesehenen +Anwendungsfällen korrekt funktioniert. Durch frühzeitiges Testen können Fehler +bereits während der Entwicklung erkannt und behoben werden. Man unterscheidet +vier Testebenen: - Akzeptanztests: Testen des gesamten Systems unter realitätsgetreuen Bedingungen @@ -17,15 +16,13 @@ beheben. Man unterscheidet dabei zwischen verschiedenen Testarten: - Integrationstests: Testen mehrerer, voneinander abhängiger Komponenten - Komponententests: Testen einzelner, abgeschlossener Softwarebausteine -Komponententests (Unit Tests) sowie Integrationstests spielen vor allem bei -agilen Vorgehensweisen wie z.B. der testgetriebenen Entwicklung (Test Driven -Development) eine große Rolle. Hierbei werden Anwendungen Schritt für Schritt -(also inkrementell) um neue Funktionen erweitert (z.B. nach der -Red-Green-Refactor-Methode): Zuerst wird ein Test geschrieben, der zunächst -fehlschlägt (Red), anschließend wird genau soviel Produktivcode geschrieben, -damit der Test erfolgreich durchläuft (Green). Schließlich werden beim -Refactoring Testcode und Produktivcode aufgeräumt (also vereinfacht und -verbessert). +Komponententests (Unit Tests) sowie Integrationstests spielen besonders bei +agilen Vorgehensweisen wie der testgetriebenen Entwicklung (Test Driven +Development) eine wichtige Rolle. Beim TDD wird eine Anwendung inkrementell nach +der Red-Green-Refactor-Methode entwickelt: Zunächst wird ein Test geschrieben, +der fehlschlägt (Red). Dann wird gerade so viel Produktivcode geschrieben, dass +der Test besteht (Green). Anschließend wird der Code aufgeräumt und vereinfacht +(Refactor). ```mermaid flowchart LR diff --git a/docs/documentation/trees.md b/docs/documentation/trees.md index a23b17f243..9100396a69 100644 --- a/docs/documentation/trees.md +++ b/docs/documentation/trees.md @@ -5,14 +5,12 @@ sidebar_position: 347 tags: [trees] --- -Bäume sind abstrakte Datenstrukturen zum Darstellen von hierarchischen -Strukturen. Sie bestehen i.d.R. aus beliebig vielen Elementen (Knoten), sowie -Verbindungen zwischen den Elementen (Kanten). Den Ursprungsknoten bezeichnet man -als _Wurzelknoten_, untergeordnete Knoten als _Kindknoten_, übergeordnete Knoten -als _Elternknoten_ und Kinder ohne weitere untergeordnete Knoten als -_Blattknoten_. Bäume sind im Prinzip Erweiterungen von Listen: in einer Liste -hat ein Knoten maximal einen Nachfolger, in einem Baum kann ein Knoten mehrere -Nachfolger besitzen. +Bäume sind abstrakte Datenstrukturen zur Darstellung hierarchischer Beziehungen. +Sie bestehen aus Knoten und Kanten zwischen den Knoten. Der oberste Knoten heißt +_Wurzelknoten_, Knoten ohne Kindknoten heißen _Blattknoten_, dazwischenliegende +Knoten sind gleichzeitig _Kind-_ und _Elternknoten_. Bäume erweitern das Konzept +der Liste: Während ein Listenknoten maximal einen Nachfolger hat, kann ein +Baumknoten mehrere Nachfolger besitzen. ```mermaid flowchart @@ -43,10 +41,9 @@ Knoten und unter dem Grad eines Knotens die Anzahl seiner Kindknoten. ## Binärbäume -Bei Binärbäumen darf jeder Knoten maximal zwei Nachfolger besitzen. Besitzen -alle inneren Knoten eines Binärbaumes den Grad 2, spricht man von einem _vollen -Binärbaum_, besitzen alle Blätter eines vollen Binärbaum die gleiche Tiefe, -spricht man von einem _vollständigen Binärbaum_. +Bei Binärbäumen hat jeder Knoten maximal zwei Nachfolger. Hat jeder innere +Knoten genau zwei Kinder, spricht man von einem _vollen Binärbaum_. Haben dabei +alle Blattknoten dieselbe Tiefe, heißt er _vollständiger Binärbaum_. ```mermaid flowchart TD @@ -89,15 +86,14 @@ flowchart TD ## Traversierung von Bäumen -Unter der Traversierung eines Baumes versteht man das Durchlaufen aller Elemente -eines Baumes. Im Gegensatz zu Listen, wo es genau eine natürliche Ordnung für -den Durchlauf der Elemente gibt (von vorne nach hinten), existieren bei Bäumen -mehrere sinnvolle Reihenfolgen: +Unter Traversierung versteht man das systematische Durchlaufen aller Knoten +eines Baumes. Anders als bei Listen, wo die Reihenfolge eindeutig ist, gibt es +bei Bäumen mehrere sinnvolle Durchlaufreihenfolgen: -- Beim Tiefendurchlauf wird ausgehend vom Wurzelknoten zunächst der linke - Teilbaum mit Tiefendurchlauf besucht, anschließend der rechte Teilbaum -- Beim Breitendurchlauf werden die Knoten nach der Breite des Baumes geordnet - besucht +- Beim Tiefendurchlauf wird ausgehend vom Wurzelknoten zuerst der linke, dann + der rechte Teilbaum rekursiv besucht. +- Beim Breitendurchlauf werden alle Knoten ebenenweise von oben nach unten + besucht. ```mermaid flowchart TD diff --git a/docs/documentation/unit-tests.md b/docs/documentation/unit-tests.md index 78d3b6af4d..4ec616ca77 100644 --- a/docs/documentation/unit-tests.md +++ b/docs/documentation/unit-tests.md @@ -5,23 +5,17 @@ sidebar_position: 320 tags: [unit-tests] --- -Komponententests (Unit Tests) werden zum Testen einzelner, abgeschlossener -Softwarebausteine verwendet. JUnit ist ein weit verbreitetes Framework zur -Erstellung dieser Komponententests bzw. zum automatisierten Testen von Klassen -und Methoden in Java. Die aktuelle Version _JUnit 5_ stellt eine Kombination -verschiedener Module der Projekte _JUnit Platform_, _JUnit Jupiter_ sowie _JUnit -Vintage_ dar. Unter einem Framework versteht man ein Programmiergerüst, welches -die Architektur für die Anwendung vorgibt und den Kontrollfluss der Anwendung -steuert. Die Arbeitsweise von Frameworks wird als _Inversion of Control_ -bezeichnet: Die Funktionen einer Anwendung werden beim Framework registriert, -welches die Funktionen zu einem späteren Zeitpunkt aufruft, d.h. die Steuerung -des Kontrollfluss obliegt nicht der Anwendung, sondern dem Framework. Die Umkehr -der Steuerung kann auch als Anwendung des Hollywood-Prinzips (_Don´t call us, -we´ll call you_) verstanden werden. +Komponententests (Unit Tests) testen einzelne, abgeschlossene Softwarebausteine +isoliert. JUnit ist das am weitesten verbreitete Framework für Unit Tests in +Java. Die aktuelle Version _JUnit 5_ setzt sich aus den Modulen _JUnit +Platform_, _JUnit Jupiter_ und _JUnit Vintage_ zusammen. Als Framework gibt +JUnit die Architektur und den Kontrollfluss der Tests vor (_Inversion of +Control_): Die Testmethoden werden beim Framework registriert, und JUnit ruft +sie auf — nach dem Hollywood-Prinzip: _Don't call us, we'll call you_. ## Implementieren einer Testklasse -JUnit-Testklassen werden mit Hilfe entsprechender Annotationen implementiert: +JUnit-Testklassen werden durch spezielle Annotationen gesteuert: - Die Annotationen `@Test` und `@ParameterizedTest` definieren einfache bzw. parametrisierte Testmethoden @@ -37,10 +31,10 @@ JUnit-Testklassen werden mit Hilfe entsprechender Annotationen implementiert: ## Zusicherungen (Assertions) -Die Klasse `Assertions` stellt verschiedene Methoden bereit, die immer dann eine -Ausnahme vom Typ `AssertionError` auslösen, wenn das Ergebnis eines -Methodenaufrufs nicht wie erwartet ausgefallen ist. Eine Ausnahme vom Typ -`AssertionError` führt dazu, dass der Test als nicht erfolgreich gewertet wird. +Die Klasse `Assertions` stellt Methoden bereit, die einen `AssertionError` +auslösen, wenn das tatsächliche Ergebnis nicht dem erwarteten Ergebnis +entspricht. Schlägt eine Zusicherung fehl, wird der Test als nicht erfolgreich +gewertet. | Assert-Methode | Bedeutung | | ---------------------------------------------------------------- | ------------------------------------------- | @@ -56,8 +50,8 @@ Methodenaufrufs nicht wie erwartet ausgefallen ist. Eine Ausnahme vom Typ ## Beispiel -Die Klasse `Calculator` stellt mehrere Methoden bereit, die getestet werden -sollen. +Die Klasse `Calculator` stellt einfache mathematische Operationen bereit, die +mit JUnit getestet werden sollen. ```java title="Calculator.java" showLineNumbers public class Calculator { @@ -79,10 +73,10 @@ public class Calculator { } ``` -Die statische Methode `setUp()` der Testklasse `CalculatorTest` stellt sicher, -dass vor der Ausführung der Testmethoden ein Taschenrechner-Objekt erzeugt wird. -In den Testmethoden werden verschiedene Testfälle wie z.B. die Division durch -Null getestet. +Die Methode `setUp()` der Testklasse `CalculatorTest` initialisiert das +Taschenrechner-Objekt vor allen Tests. Die Testmethoden decken verschiedene +Szenarien ab, darunter die Multiplikation mit null, Absolutwerte und die +Division durch null. ```java title="MainClass.java" showLineNumbers public class CalculatorTest { @@ -119,10 +113,9 @@ public class CalculatorTest { :::info -Für die Benennungen von Testmethoden wird in der Regel versucht, die -wesentlichen Informationen eines Tests (Name der zu testenden Methode, -vorgegebener Zustand, zu erwartendes Verhalten) in den Methodennamen zu -integrieren. Zusätzlich können Schlüsselwörter wie _Should_, _When_, oder _Then_ -verwendet werden. +Für die Benennung von Testmethoden hat sich das Muster +`methodName_zustand_erwartung` bewährt (z.B. +`divide_byZero_ArithmeticException`). Zusätzlich können Schlüsselwörter wie +_should_, _when_ oder _then_ eingesetzt werden. ::: diff --git a/docs/documentation/wrappers.md b/docs/documentation/wrappers.md index 819303807a..2b6738684f 100644 --- a/docs/documentation/wrappers.md +++ b/docs/documentation/wrappers.md @@ -5,30 +5,29 @@ sidebar_position: 141 tags: [java-api, wrappers] --- -Wrapper-Klassen (auch Hüllenklassen genannt) verpacken primitive Datentypen in -vollwertigen Klassen und erweitern so die primitiven Datentypen um hilfreiche -Methoden. Das Verpacken eines primitiven Datentyps bezeichnet man als _Boxing_, -das Entpacken als _Unboxing_. +Wrapper-Klassen (auch _Hüllenklassen_ genannt) verpacken primitive Datentypen in +vollwertige Objekte und erweitern sie so um nützliche Methoden. Das Verpacken +eines primitiven Werts nennt man _Boxing_, das Entpacken _Unboxing_. Java führt +diese Konvertierung in vielen Kontexten automatisch durch (_Autoboxing_). ```java title="MainClass.java" showLineNumbers public class MainClass { public static void main(String[] args) { - Integer i = Integer.valueOf("631"); + Integer i = Integer.valueOf("631"); // String in Integer umwandeln System.out.println(i); - Boolean b = Boolean.logicalXor(true, false); + Boolean b = Boolean.logicalXor(true, false); // logisches XOR System.out.println(b); - Character c = Character.toUpperCase('a'); + Character c = Character.toUpperCase('a'); // Zeichen in Großbuchstaben System.out.println(c); } } ``` -:::info +:::note -Wrapper-Klassen basieren auf dem Entwurfsmuster _Adapter_, welches die -Kommunikation zwischen Klassen mit zueinander inkompatiblen Schnittstellen -ermöglicht. +Wrapper-Klassen basieren auf dem Entwurfsmuster _Adapter_, das die Kommunikation +zwischen Klassen mit inkompatiblen Schnittstellen ermöglicht. :::