Benutzer-Werkzeuge

Webseiten-Werkzeuge


phwt:skriptjava

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

phwt:skriptjava [2015-01-04 19:12] (aktuell)
Zeile 1: Zeile 1:
 +====== Skript zur Vorlesung Grundlagen der Informatik I (Java) ======
 +
 +URL dieses Dokuments: http://​wiki.macke.it/​doku.php/​fhwt:​skriptjava
 +
 +===== Einführung in Java =====
 +Java ist eine Compilersprache,​ was bedeutet, dass der **Quelltext**,​ den ein Programmierer erstellt, von einem speziellen Übersetzungsprogramm - dem **Compiler** - in ausführbaren **Maschinencode** übersetzt werden muss.
 +Die Besonderheit bei Java ist dabei, dass der erzeugte Maschinencode nicht plattformspezifisch ist, sondern auf der Java Virtual Machine (**JVM**) ausführbar ist, die es für so ziemlich jedes Betriebssystem gibt.
 +Daher sind Javaprogramme plattformunabhängig (eine Programmiersprache -> viele Plattformen). Der vom Compiler erzeugte Maschinencode heißt **Bytecode**.
 +Im Vergleich dazu verfolgt Microsofts .NET Framework den Ansatz, mit mehreren Programmiersprachen (C#, Visual Basic
 +usw.) eine Plattform (Windows) zu bedienen (wobei es z.B. mit Mono auch schon eine Implementierung von .NET für Linux gibt).
 +
 +Der normale Ablauf beim Programmieren ist:
 +  - Quelltext im  Editor eingeben
 +  - Quelltext mit dem Compiler in Bytecode übersetzen
 +  - Bytecode auf der Java-VM ausführen
 +
 +Die Java-VM ist Bestandteil des Java Runtime Environment (**JRE**), dass auf einem Betriebssystem installiert sein muss, damit man Java-Programme ausführen kann.
 +Im Gegensatz dazu enthält das sog. Java Development Kit (**JDK**) zusätzliche Programmierwerkzeuge (insb. den Compiler), um selbst Programme zu erstellen.
 +
 +Ein einfaches Beispielprogramm in Java sieht z.B. so aus:
 +<code java>​public class HelloWorld ​
 +{
 +    public static void main(String[] args)
 +    {
 +        System.out.println("​Hello World!"​);​
 +    }
 +}</​code>​
 +
 +Dieses Programm muss in einer Datei ''​HelloWorld.java''​ gespeichert und dann mit ''​javac HelloWorld.java''​ kompiliert
 +werden. Dazu muss ''​javac.exe''​ im ''​PATH''​ liegen. Danach kann das Programm mit ''​java HelloWorld''​ aufgerufen werden.
 +Wichtig: Die Datei muss exakt so heißen wie die Klasse, die in ihr definiert wird. Groß- und Kleinschreibung wird unterschieden (Java ist **case-sensitive**).
 +
 +Des weiteren ist es sehr wichtig, die **Syntax** der Programmiersprache exakt einzuhalten. Schon der kleinste Tippfehler kann dazu führen, dass das Programm nicht mehr kompiliert werden kann. Hier ist ein Beispielprogramm,​ das einige Syntaxfehler enthält:
 +<code java>​static void main(String arg[]) {
 +System.out.Println(Die Zahl ist 127 )
 +System.out.Println(Das doppelte davon ist  2*127)
 +System.out.Println(ENDE)</​code>​
 +
 +  * ''​class''​-Definition fehlt
 +  * ''​public''​ vor ''​main()''​ fehlt
 +  * ''​Println''​ muss ''​println''​ lauten
 +  * die Anführungszeichen um die Texte fehlen
 +  * fehlende Semikolons am Zeilenende
 +  * fehlende Klammern ''​}''​
 +
 +Für Menschen ist es schwierig, an all diese Dinge zu denken. Daher gibt es Programmierwerkzeuge,​ die einem diese Arbeit abnehmen. Das bekannteste Beispiel im Java-Umfeld ist **Eclipse**,​ ein Integrated Development Environment (**IDE**).
 +Insbesondere bei der Teamarbeit mit Hilfe einer zentralen Quelltextverwaltung wie z.B. Subversion (SVN) ist es sinnvoll, dass alle Teammitglieder die gleichen Einstellungen bzgl. der Quelltextformatierung verwenden, damit es bei Änderungen keine Unterschiede aufgrund von Formatierungsoptionen gibt.
 +
 +===== Elementare Datentypen =====
 +Für bestimmte wichtige Daten sind in Java sog. **elementare Datentypen** (auch **primitive** Datentypen genannt) definiert. Die wichtigsten sind:
 +  * ''​short'',​ ''​int''​ und ''​long''​ für Ganzzahlen
 +  * ''​float''​ und ''​double''​ für Gleitkommazahlen
 +  * ''​char''​ für einzelne Zeichen
 +  * ''​bool''​ für Wahrheitswerte
 +
 +Als Dezimaltrennzeichen wird nicht ein Komma, sondern ein Punkt verwendet.
 +Bei langen Zahlen vom Datentyp Long ist es sinnvoll, ein "​L"​ als Suffix zu verwenden. ​
 +
 +Den Wertebereich der numerischen Datentypen kann man mittels der Konstanten ''​MIN_VALUE''​ und ''​MAX_VALUE''​ herausfinden. ​
 +
 +Beispiel:
 +<code java>​System.out.println("​short kann Werte von " + Short.MIN_VALUE + " bis " + Short.MAX_VALUE + " aufnehmen."​);​
 +System.out.println("​int kann Werte von " + Integer.MIN_VALUE + " bis " + Integer.MAX_VALUE + " aufnehmen."​);​
 +System.out.println("​long kann Werte von " + Long.MIN_VALUE + " bis " + Long.MAX_VALUE + " aufnehmen."​);​
 +System.out.println("​float kann Werte von " + Float.MIN_VALUE + " bis " + Float.MAX_VALUE + " aufnehmen."​);​
 +System.out.println("​double kann Werte von " + Double.MIN_VALUE + " bis " + Double.MAX_VALUE + " aufnehmen."​);</​code>​
 +
 +Mit dem char '​\n'​ kann ein Zeilenumbruch verursacht werden, mit dem char '​\t'​ ein Tab-Stop.
 +
 +^ Datentyp ^ Byte ^ Wertebereich ^
 +| Byte     | 1 | -128 bis 127 |
 +| Short    | 2 | -32.768 bis 32.767 |
 +| Integer ​ | 4 | -2.147.483.648 bis 2.147.483.647 |
 +| Long     | 8 | -18.446.744.073.709.551.616 bis 18.446.744.073.709.551.615 |
 +
 +Um Zahlen aus anderen Zahlsystemen sichtbar zu machen, können die Präfixe "​0b"​ für binäre, "​0"​ für oktale und "​0x"​ für hexadezimale Zahlen verwendet werden. ​
 +Intern werden alle Zahlen jedoch dezimal gespeichert.
 +
 +===== Arten von Klammern =====
 +
 +{} curly braces
 +() parenthesis
 +<> angle brackets
 +[] brackets
 +
 +===== Camel Case =====
 +
 +Der Camel Case ist eine Konvention zur Benennung von Variablen, Methoden und Methodenparametern.
 +Für sie ist kennzeichnend,​ dass das erste Zeichen eines Bezeichners grundsätzlich klein geschrieben wird.
 +Innerhalb des Bezeichners werden Groß- und Kleinschreibung gemischt verwendet, wobei das erste Zeichen jedes
 +den Bezeichner konstituierenden Wortes groß geschrieben wird.
 +
 +Beispiele:
 +userName
 +deleteUser
 +createBankAccount
 +logoutAndShutdown
 +
 +===== Variablen =====
 +Die wichtigsten Elemente der meisten Programmiersprachen sind die sog. **Variablen**. Variablen sind benannte Speicherbereiche,​ die Daten aufnehmen können. Sie werden **deklariert** (Datentyp und Name werden festlegen) und **initialisiert** (Wert wird zugewiesen).
 +Der Inhalt einer Variablen kann dann über ihren Namen ausgelesen werden.
 +
 +Beispiel: ​
 +<code java>int zahl = 1;
 +System.out.println("​zahl hat den Wert: " + zahl);</​code>​
 +
 +In Java müssen Variablen initialisiert werden, bevor sie wie im Beispiel verwendet werden können. Dieses Beispiel würde daher einen Fehler erzeugen:
 +<code java>int zahl;
 +System.out.println(zahl);</​code>​
 +
 +Die **Bezeichner** (Namen) der Variablen dürfen beliebig lang sein und Buchstaben, Zahlen und bestimmte Sonderzeichen (z.B. ''​-'',​ ''​_'',​ ''​$''​) enthalten. Sie dürfen jedoch nicht mit einer Zahl beginnen.
 +Obwohl es möglich ist, rate ich von der Verwendung von Umlauten und anderen Sonderzeichen wie ''​ß''​ in Java-Bezeichnern dringend ab. Zum besseren Verständnis sollte man sich auf eine Sprache einigen. Wir arbeiten grundsätzlich mit Englisch.
 +Laut Konvention werden Variablen-Namen in Java kleingeschrieben und dann in der sog. **CamelCase**-Notation fortgesetzt:​ ''​int diesIstEineGrosseZahl;''​
 +Bestimmte Zählvariablen haben meist nur einen einzelnen Buchstaben als Namen. Ansonsten sollten unbedingt sprechende (=lange) Namen verwendet werden, da dies die Programme leichter lesbar und verständlicher macht.
 +  ​
 +Da Java eine **statisch typisierte** Programmiersprache ist, muss allen Variablen ein Datentyp zugewiesen werden. ​
 +Dieser Datentyp ist im Nachhinein nicht mehr änderbar. Folgendes Beispiel würde daher zu einem Fehler führen:
 +<code java>int zahl = 1;
 +zahl = "​text";</​code>​
 +
 +==== Gültigkeitsbereich von Variablen (Scope) ====
 +Variablen haben einen sogenannten Gültigkeitsbereich,​ den **Scope**. Sie sind nur innerhalb des Blocks verfügbar, in dem
 +sie definiert wurden, und in allen Blöcken innerhalb dieses Blocks. Ein Block ist ein Codebereich,​ der mit geschweiften
 +Klammern umschlossen ist. Man kann in seinem Code beliebige Blöcke definieren und einige Sprachkonstrukte (wie z.B.
 +''​class'',​ ''​if''​ und ''​for''​) benötigen auch explizit einen Block.
 +
 +Beispiel:
 +<code java>int test = 1;
 +{
 +    int test2 = 2;
 +    // 1
 +    {
 +        int test3 = 3;
 +        // 2
 +    }
 +    // 3
 +}
 +// 4</​code>​
 +
 +  * 1: ''​test''​ und ''​test2''​ sind verwendbar
 +  * 2: ''​test'',​ ''​test2''​ und ''​test3''​ sind verwendbar
 +  * 3: ''​test''​ und ''​test2''​ sind verwendbar
 +  * 4: ''​test''​ ist verwendbar
 +
 +==== Konstanten ====
 +Es gibt Variablen, die sich während des Programmablaufs verändern können. Im Gegensatz dazu stehen die **Konstanten**,​ deren zugewiesener Wert, nicht im Programmablauf verändert werden kann.
 +Dies bewirkt, dass zentrale Werte nicht überschrieben werden können, und die Konstante in anderen Programmteilen
 +widerverwendet werden kann. 
 +
 +Laut Konvention werden Bezeichner von Konstanten in Java in Großbuchstaben und mit Unterstrichen getrennt geschrieben. Damit eine verändere Variable zu einer 
 +Konstante wird, ist der Modifizierer **final** notwendig. Ein Schreibzugriff auf eine Konstante, führt zu einer Fehlermeldung.
 +
 +Beispiel:
 +<code java> public static final int MWST_SATZ = 19;</​code>​
 +
 +==== Casts ====
 +Mit Hilfe von **Casts** kann man Datentypen in andere Datentypen umwandeln.
 +<code java>int number1 = 123;
 +double decimal1 = number1; // impliziter Cast ohne Wertverlust ​
 +decimal1 = 123.45;
 +int number2 = (int) decimal1; // expliziter Cast mit Wertverlust</​code>​
 +
 +  * Beim Casten von Integer-Variablen zu Double gibt es keine Probleme, da der Wertebereich von Double größer ist als der von Integer.
 +  * Beim Casten von Double zu Integer wird der Dezimalwert nach dem Komma "​abgeschnitten"​.
 +
 +Des Weiteren ist das Casten von Character zu Integer und umgekehrt möglich.
 +
 +<code java>int asciiPositionOfA = '​A';​
 +System.out.println(asciiPositionOfA);​
 +char characterAtPosition65 = (char) 65;
 +System.out.println(characterAtPosition65);</​code>​
 +
 +Um Werte in Strings zu konvertieren,​ besitzt jeder Datentype die Methode ''​toString()''​. Dazu muss man jedoch die 
 +Klassen der Datentypen verwenden. Die elementaren Datentypen wie ''​int'',​ ''​double''​ und ''​boolean''​ besitzen keine Klasse.
 +Es gibt jedoch für jeden elementaren Datentyp auch eine enstprechende Klasse (''​Integer'',​ ''​String'',​ ''​Double'',​
 +''​Boolean''​ usw.).
 +
 +<code java>​Integer int1 = 20;
 +String numberStr = int1.toString();​
 +System.out.println(numberStr + 3); // -> 203
 +
 +String numberToParse = "​20.50";​
 +double parsedNumber = Double.parseDouble(numberToParse);​
 +System.out.println(parsedNumber + 3); // -> 23.5</​code>​
 +
 +==== Arrays ====
 +Ein Array ist eine Liste mit mehreren Elementen eines bestimmten Datentyps. ​
 +Der Datentyp muss angegeben werden sowie auch die Länge, die später nicht mehr geändert werden kann.
 +Eine Array muss wie folgt angelegt werden, wichtig ist dabei das Schlüsselwort ''​new'': ​
 +<code java>​Datentyp[] Bezeichner = new Datentyp[Länge des Arrays];</​code>​
 +Der Vorteil von Arrays ist, dass mehrere Werte einfach verarbeitet werden können (z.B. mit einer ''​for''​-Schleife),​
 +wobei Redundanzen im Code (z.B. ''​var1'',​ ''​var2'',​ ''​var3''​ etc.) vermieden werden.
 +
 +===== Ausdrücke und Anweisungen =====
 +Die sog. **Ausdrücke** verknüpfen **Literale** (wie Zahlen oder Zeichenketten),​ Variablen oder Konstanten mit **Operatoren** (z.B. ''​+'',​ ''​*''​ usw.) und liefern dabei meist einen Wert zurück.
 +
 +Beispiel: ​
 +<code java>int sum = x + y + 10;</​code>​
 +
 +  * Literale: ''​10''​
 +  * Variablen: ''​x'',​ ''​y''​
 +  * Operatoren: ''​=''​ (Zuweisung),​ ''​+''​ (Addition)
 +  * Ausdruck: ''​x + y + 10''​ (Rückgabewert ist die Summe von x, y und 10)
 +
 +Das gesamte Konstrukt aus dem Beispiel nennt man **Anweisung**. Alle Anweisungen in Java müssen mit einem Semikolon abgeschlossen werden.
 +
 +==== Grundlegende Arithmetik ====
 +Die grundlegenden Operationen der Mathematik können in Java sehr einfach verwendet werden:
 +
 +<code java>int result = 1 + 5 * 3 - 4 / 2;
 +double result2 = (1 + 5) * (3 - 4) / 2</​code>​
 +
 +Man muss jedoch auf den korrekten Datentyp achten, da ansonsten ggfs. Wertverluste auftreten (insb. bei der Division).
 +<code java>​double result = 1 / 2; // -> 0
 +result = 1.0 / 2; // -> 0.5</​code>​
 +
 +Eine wichtige Operation ist die Division mit Rest, der **Modulo**:
 +
 +<code java>int remainder = 10 % 4; // -> 2</​code>​
 +
 +Weitere wichtige mathematische Werte und Funktionen - wie das Wurzelziehen,​ die Potenzrechnung oder die Zahl Pi - sind im Package
 +''​Math''​ definiert:
 +<code java>​System.out.println(Math.sqrt(9));​ // -> 3
 +System.out.println(Math.PI);​ // -> 3.14...
 +System.out.println(Math.pow(2,​ 10)); // -> 1024</​code>​
 +
 +Zusätzlich sind eigene Operatoren für das **Inkrementieren** und **Dekrementieren** von Ganzzahlen verfügbar:
 +
 +<code java>int x = 5;
 +System.out.println(x++);​ // Post-Increment -> x wird erst nach dem Ausgeben erhöht
 +System.out.println(++x);​ // Pre-Increment -> x wird vor dem Ausgeben erhöht
 +System.out.println(x--);​ // Post-Decrement -> x wird erst nach dem Ausgeben verringert
 +System.out.println(--x);​ // Pre-Decrement -> x wird vor dem Ausgeben verringert</​code>​
 +
 +==== Vergleiche und grundlegende Boolesche Algebra ====
 +Es gibt verschiedene Vergleichsoperatoren für logische Vergleiche:
 +  * ''​==''​ (gleich)
 +  * ''<''​ (kleiner)
 +  * ''>''​ (größer)
 +  * ''<​=''​ (kleiner gleich)
 +  * ''>​=''​ (größer gleich)
 +  * ''​!=''​ (ungleich)
 +
 +Das ''​=''​ kann nicht zum Vergleichen verwendet werden, da es sich hierbei um den **Zuweisungsoperator** handelt.
 +
 +<code java>​System.out.println(3 < 5); // -> true
 +System.out.println(3 == 5); // -> false
 +System.out.println(4 > 8); // -> false</​code>​
 +
 +Das Ergebnis eines Vergleichs kann auch in einer Variablen gespeichert werden:
 +
 +<code java>​boolean comparison = 3 > 2;
 +System.out.println(comparison);​ // -> true</​code>​
 +
 +**Boolesche** Werte können mit AND, OR, XOR und NOT kombiniert werden:
 +
 +<code java>​System.out.println("​true AND false: " + (true && false)); // -> false
 +System.out.println("​true OR false: " + (true || false)); // -> true
 +System.out.println("​true XOR false: " + (true ^ false)); // -> true
 +System.out.println("​NOT false: " + (!false)); // -> true</​code>​
 +
 +===== Algorithmen =====
 +Ein **Algorithmus** ist eine Handlungsvorschrift (ein "​Rezept"​) zum Lösen eines Problems. Er umfasst eine endliche Anzahl an
 +Handlungsschritten. Alle Algorithmen können aus drei grundlegenden "​Bausteinen"​ zusammengesetzt werden: Sequenz, Verzweigung und Wiederholung.
 +
 +==== Sequenz ====
 +Ein Folge von mehreren Anweisungen wird als Sequenz bezeichnet.
 +
 +<code java>int ergebnis = 3 + 5;
 +ergebnis = ergebnis * 8;
 +ergebnis++;
 +System.out.println(ergebnis);​ // -> 65</​code>​
 +
 +==== Verzweigung ====
 +Die Verzweigung ist ein grundlegendes Strukturelement für Fallunterscheidungen innerhalb eines Algorithmus.
 +Sie bewirkt die Entscheidung für eine von zwei Möglichkeiten. ​
 +
 +<code java>if (boolescher Ausdruck)
 +{
 +    Anweisung, die ausgeführt wird, wenn der obige Ausdruck ''​true''​ ist
 +}
 +else 
 +{
 +    Anweisung, die ausgeführt wird, wenn der obige Ausdruck ''​false''​ ist
 +}</​code>​
 +
 +==== Wiederholung ====
 +Es gibt drei grundlegende Arten von Wiederholungen (Schleifen).
 +  * die zählergesteuerte Schleife
 +  * die kopfgesteuerte Schleife
 +  * die fußgesteuerte Schleife
 +
 +Die **zählergesteuerte Schleife** kann verwendet werden, wenn bekannt ist, wie viele Wiederholungen durchgeführt werden sollen.
 +
 +Aufbau:
 +<code java>for (Startwert; Abbruchbedingung;​ Aktion) {}</​code>​
 +Abfolge einer **for-Schleife**:​
 +
 +  - **Deklaration und Initialisierung** der Laufvariablen,​ bzw. Zuwei-sung eines Startwertes falls Variable ausserhalb der Schleife deklariert wurde
 +  - **Start der Schleife** (nicht Ausführung des Codes im Anweisungsblock der Schleife)
 +  - **Prüfung der Abbruchbedingung:​**
 +    * Bedingung wahr? Ausführung des Anweisungsblocks
 +    * Bedingung unwahr? Ende der Schleife, Fortsetzung des Programms
 +  - **Manipulation der Laufvariablen** im Aktionsteil
 +  - **Sprung** zur Prüfung der **Abbruchbedingung** ( **3.** )
 +
 +Beispiel:
 +<code java>for (int i=0; i <= 100; i++)
 +{
 +    System.out.println(i);​
 +}</​code>​
 +
 +Die **kopfgesteuerte Schleife** sollte verwendet werden, wenn vor dem ersten Durchlauf schon die Bedingung geprüft werden muss.
 +
 +Aufbau:
 +<code java>​while (Abbruchbedingung) {}</​code>​
 +
 +Die **fußgesteuerte Schleife** sollte verwendet werden, wenn mindestens eine Wiederholung durchgeführt werden und die Bedingung erst nach dem Durchlauf geprüft werden soll.
 +
 +Aufbau:
 +<code java>do { } while (Abbruchbedingung)</​code>​
 +
 +Eine **Endlosschleife** entsteht dann, wenn die Abbruchbedingung nie erfüllt wird und die Schleife daher immer wieder durchlaufen wird.
 +
 +=== Anwendung von continue in Schleifen ===
 +**"​Continue"​** bewirkt, dass die aktuell laufende Wiederholung einer Schleife abgebrochen wird. Es wird zum Ende des Anweisungsblocks gesprungen. Alle nachfolgenden Anweisungen kommen in diesem Schleifendurchlauf nicht mehr zur Ausführung. Die Schleife kann ggf. dennoch weiter durchlaufen werden.
 +Beispiel:
 +<code java> ​ int i = 5;
 + while (i > 0)
 + {
 + i--;
 +
 + if (i == 2)
 + {
 + continue; ​ // -> die 2 wird bei dem Schleifendurchlauf nicht ausgegeben.
 + }
 +
 + System.out.println(i);​
 + }</​code>​
 +
 +=== break in Schleifen ===
 +Die Anwendung von **break** veranlasst, im Gegensatz zu continue nicht nur das Abbrechen der aktuellen Schleifenwiederholung,​ sondern den **Komplettabbruch** der Schleife.
 +
 +===== Methoden (Funktionen) =====
 +In Java werden Funktionen **Methoden** genannt. Sie kapseln Code und können bei Bedarf von verschiedenen Stellen aus aufgerufen werden (Wiederverwendung).
 +Methodenbezeichner können wie die von Variablen frei gewählt werden. Es gelten die gleichen Namenskonvention wie bei Variablen.
 +
 +Aufbau: ''​Rückgabetyp Name(Parameter) { Implementierung }''​
 +
 +Parameter und innerhalb der Methode definierte Variablen sind nur innerhalb dieser Methode gültig (siehe Scope). Die Kommunikation erfolgt über einen (!) Rückgabewert (Schlüsselwort ''​return''​). ​
 +Beachte: ''​return''​ verlässt die Methode, d.h. weiterer Code in der Methode ist unerreichbar (der Compiler merkt das auch).
 +Der Rückgabetyp ist nicht immer zwingend ein Wert. Er kann auch leer sein, z.B. bei ''​System.out.println()'':​ Rückgabetyp ist ''​void''​ = kein Rückgabewert.
 +Name + Parameter = **Signatur** der Methode (z.B. ist ''​System.out.println()''​ mehrfach definiert mit unterschiedlichen Parametern. Welche konkrete Methode ausgeführt wird, entscheiden die Parameter (''​true'',​ ''"​fdfhdfh"'',​ ''​1''​ etc.)
 +
 +==== Rekursion ====
 +Als **Rekursion** bezeichnet man das Aufrufen einer Methode aus derselben Methode heraus. Beispiele: Fakultätenberechnung (''​fak(n) = n * fak(n - 1);''​),​ Suchen durch ein Dateisystem.
 +**Achtung:​** Rekursion ist sehr teuer, da viel Platz auf dem Stack benutzt wird. Es besteht die Gefahr eines StackOverflows,​ bei dem der Speicherplatz des Stacks nicht mehr ausreicht.
 +Das Gegenteil ist die **Iteration**. Man kann alle rekursiven Berechnungen auch iterativ lösen.
 +
 +===== Exceptions =====
 +Bei der Programmausführung können Fehler auftreten, z.B. wenn durch 0 geteilt wird. Um mit diesen Fehlern umgehen zu
 +können, gibt es die sogenannten **Exceptions**. In Java werden Exceptions "​geworfen",​ wenn ein Fehler auftritt. Sie
 +können dann im Code "​aufgefangen"​ werden, um sie zu behandeln.
 +
 +Anweisungen,​ von denen der Entwickler weiß oder vermutet, dass sie einen Fehler erzeugen könnten, fasst er in **try-catch-Blöcke** ein.
 +Das Programm durchläuft zunächst den ''​try''​-Block und springt in den ''​catch''​-Block,​ sobald eine Exception auftritt.
 +Wenn keine Exception auftritt, wird der ''​catch''​-Block nicht durchlaufen. Soll in beiden Fällen, also unabhängig vom
 +Auftreten eines Fehlers, ein weiterer Codeteil durchlaufen werden, wird dieser in den ''​finally''​-Block hinter dem
 +''​catch''​-Block geschrieben.
 +
 +**Es ist dringend davon abzuraten, dass Exceptions durch einen leeren ''​catch''​-Block "​geschluckt"​ werden.** Vielmehr
 +sollte im ''​catch''​-Block der Fehler behandelt werden oder zumindest eine sinnvolle Fehlermeldung an den Benutzer
 +ausgegeben werden.
 +
 +Alle Methoden in Java, die im Laufe ihrer Ausführung eine Exception auslösen könnten, müssen dies explizit kenntlich
 +machen. Dies geschieht bei der Definition der Methode durch die Verwendung des Schlüsselwortes **throws**. Dadurch wird
 +sichergestellt,​ dass alle Aufrufer dieser Methode immer ein ''​try/​catch''​ nutzen müssen, wenn sie die Methode aufrufen
 +wollen.
 +
 +Der Entwickler selbst kann manuell eine Exception erzeugen, indem er im Code mittels **throw** eine Exception wirft.
 +
 +Beispiel:
 +<code java>​double divide(int a, int b) throws Exception
 +{
 +    if (b == 0)
 +        throw new Exception("​b darf nicht 0 sein."​);​
 +    return (double)a / b;
 +}
 +void test()
 +{
 +    double result;
 +    try
 +    {
 +        double = divide(1, 0);
 +    }
 +    catch (Exception e)
 +    {
 +        System.out.println("​Fehler bei der Berechnung: " + e.getMessage());​
 +        result = 0;
 +    }
 +}</​code>​
 +
 +===== Objektorientierung =====
 +
 +==== Was sind Objekte? ====
 +Ein Objekt ist ein "​Ding"​ der realen Welt, das in der Software abgebildet werden soll. Ein Objekt kann alles sein: ein Auto, ein Vertrag, eine Tür, etc.
 +Ein Objekt hat Funktionen und Eigenschaften. Eine Funktion eines Autos ist z.B. 'Gas geben' und eine Eigenschaft ist
 +'​Farbe'​. Die Funktionen heißen in der OO **Methoden** und die Eigenschaften nennt man **Attribute**.
 +
 +==== Klasse vs. Objekt ====
 +Eine Klasse definiert die abstrakten Charakteristika eines Objekts, z.B. dass alle Hunde vier Beine haben und bellen können. Sie dient als Bauplan/​Schablone für Objekte.
 +Ein Objekt ist dann eine konkrete **Instanz** dieser Klasse, z.B. der Schäferhund mit Namen Rex.
 +In Java werden Klassen geschrieben. Eine Klasse ist gleichzusetzen mit einem Datentyp. Es könnte also eine Klasse ''​Car''​ geben, wobei Car dann der Datentyp wäre.
 +Die Attribute sind Variablen, die direkt unterhalb der Klasse definiert werden (also nicht in einer Methode). Diese Variablen können in allen Methoden der Klasse verwendet werden (siehe Scope).
 +Methoden werden ebenfalls auf Ebene der Klasse definiert und können damit intern verwendet werden, aber auch von außen aufgerufen werden (wie z.B. ''​s.charAt(1);'',​ wobei ''​s''​ dann der Name des Objektes ist).
 +
 +Beispiel:
 +<code java>​class Auto
 +{
 +    String farbe;
 +
 +    void gibGas()
 +    {
 +        System.out.println("​Brumm brumm"​);​
 +    }
 +}</​code>​
 +
 +Ein Objekt wird erstellt, indem der Konstruktor der Klasse aufgerufen wird. Konstruktoren sind besondere Methoden, deren Name mit dem der Klasse ​
 +übereinstimmen muss und die keinen Rückgabewert haben. Ist kein expliziter Konstruktor angegeben, erzeugt Java automatisch einen Default-Konstruktor ohne Parameter.
 +Wenn man selbst einen Konstruktor erstellt, wird der Default-Konstruktor nicht erzeugt und es kann nur noch mit dem angegebenen Konstruktor gearbeitet werden.
 +Man kann beliebig oft den Konstruktor einer Klasse aufrufen und dabei wird jedes Mal ein völlig neues Objekt erstellt, mit dem dann gearbeitet wird.
 +
 +Beispiel:
 +<code java>​class Auto
 +{
 +    String farbe;
 +
 +    Auto(String farbe)
 +    {
 +        this.farbe = farbe;
 +    }
 +}</​code>​
 +
 +
 +==== Kapselung ====
 +Bei der Objektorientierung soll möglichst alles so implementiert werden, dass einzelne Programmteile **gekapselt** sind. Dies hat drei Gründe:
 +  - Übersichtlichkeit:​ Der Code bleibt lesbar und ist schneller nachzuvollziehen.
 +  - Wiederverwendbarkeit:​ Die einzelnen Teile können relativ einfach in anderen Programmen wiederverwendet werden.
 +  - Sicherheit: Die Code-Teile kommen sich nicht in die Quere und können nicht versehentlich auf bereits vergebene Variablen o.ä. zugreifen.
 +
 +==== Sichtbarkeit ====
 +Die Sichtbarkeit beschreibt, wer Elemente (Klassen, Variablen und Methoden) nutzen kann. Es gibt drei Sichtbarkeitmodifikatoren:​
 +  * private - Das Element ist nur innerhalb der aktuellen Klasse sichtbar.
 +  * public - Das Element ist für alle sichtbar.
 +  * protected - Das Element ist innerhalb der aktuellen Klasse und in abgeleiteten Klassen sichtbar.
 +
 +^           ^ Selbst ^ Subklassen ^ Welt ^
 +| private ​  | x      |            |      |
 +| protected | x      | x          |      |
 +| public ​   | x      | x          | x    |
 +
 +Bei der Implementierung von Klassen ist darauf zu achten, dass Attribute grundsätzlich als ''​private''​ zu kennzeichnen sind!
 +Grund: Andernfalls könnte man Objekten von außen ungültige Werte setzen (z.B. Alter = -1).
 +Um ''​private''​-Variablen auch außerhalb der Klasse benutzen zu können, werden **Getter** und **Setter** verwendet:
 +  * Getter: Methode, die nur die Variable zurückgibt:​ ''​car.getColor()''​
 +  * Setter: Methode, die es ermöglicht,​ die Variable zu ändern: ''​car.setColor("​green"​);''​
 +
 +==== Vererbung ====
 +Die **Vererbung** ist eine zentrale Funktion der Objektorientierung und bedeutet, dass Klassen von einer anderen Klasse
 +Methoden und Attribute erben können. Diese Methoden und Attribute werden dadurch wiederverwendbar. Die erbende Klasse
 +heißt **Subklasse** oder **abgeleitete Klasse**, die vererbende Klasse heißt **Basisklasse**.
 +
 +Das Schlüsselwort ''​extends''​ gibt die Basisklasse zu einer Subklasse an. Hier erbt die Klasse ''​Circle''​ von der Klasse
 +''​Shape''​. Mit dem Schlüsselwort ''​super''​ hat man die Möglichkeit den Konstruktor der Basisklasse aufzurufen.
 +
 +<code java>​public class Circle(int originX, int originY, int radius) extends Shape
 +{
 +    super(originX,​ originY);
 +    this.radius = radius;
 +}</​code>​
 +
 +Mit der Annotation ''​@Override''​ werden Methoden gekennzeichnet,​ die gleichnamige Methoden ihrer Basisklasse **überschreiben**.
 +<code java>​public class A 
 +{
 +    public void eineMethode() {}
 +}
 +
 +public class B extends A 
 +{
 +    @Override
 +    public void eineMethode() {}
 +}</​code>​
 +
 +
 +Durch das Schlüsselwort ''​final''​ kann eine Methode nicht in einer Subklasse überschrieben werden. Das Schlüsselwort
 +''​abstract''​ definiert eine Methode oder eine ganze Klasse als **abstrakt**. Abstrakte Klassen können nicht instantiiert
 +werden. Eine abstrakte Methode definiert lediglich ihre Signatur, und eine Subklasse muss diese Methode dann implementieren.
 +Die Klasse ist dann nur für den Kopf der Methode zuständig, während die Implementierung an anderer Stelle erfolgt. Durch abstrakte Methoden ​
 +wird ausgedrückt,​ dass die Basisklasse keine Ahnung von der Implementierung hat und dass sich die Unterklassen darum kümmern müssen.
 +
 +<code java>​public abstract class MyVehicle
 +{
 +    // die Methode getType wird für die Subklassen vorgegeben
 +    abstract protected String getType();
 +}
 +
 +public class MyCar extends MyVehicle
 +{
 +    // die Subklasse überschreibt die abstrakte Methode und implementiert etwas Konkretes
 +    @Override
 +    protected String getType()
 +    {
 +        return "​car";​
 +    }
 +}</​code>​
 +
 +==== UML ====
 +Die UML (**Unified Modeling Language**) ist eine grafische Beschreibungssprache,​ die insb. in der objektorientierten
 +Softwareentwicklung zur Modellierung und Dokumentation eingesetzt wird.
 +
 +Es gibt in Version 2.0 13 verschiedene Diagrammtypen. Die wichtigsten sind:
 +  * Klassendiagramm
 +  * Sequenzdiagramm
 +  * Verteilungsdiagramm
 +  * Aktivitätsdiagramme
 +  * Zustandsautomaten
 +
 +=== Klassendiagramm ===
 +Ein Klassendiagramm ist ein Strukturdiagramm zur Modellierung von Klassen, Schnittstellen und deren Beziehungen.
 +Ein Klassendiagramm zeigt also, in welcher Beziehung Klassen zueinander stehen (z.B. Basisklasse und Subklassen).
 +Zudem gibt das Diagramm die Attribute und Methoden der Klassen an.
 +
 +Beispieldiagramm:​
 +http://​upload.wikimedia.org/​wikipedia/​commons/​0/​03/​Klassendiagramm-1.png
 +
 +===== Automatische Tests =====
 +In Java gibt es die Möglichkeit,​ den geschriebenen Code durch einen Testcode testen zu lassen. Dazu wird meist das Framework '​JUnit'​ verwendet.
 +JUnit ist ein Framework für Unit-Tests und stellt die nötigen Funktionen zum Testen von Code bereit (insb. die
 +sogenannten **Assertions**). Ein JUnit-Test sieht wie folgt aus:
 +
 +<code java>​@Before // wird vor JEDEM Test ausgeführt und sorgt dafür, dass das Testobjekt in seinen Initialzustand versetzt wird
 +public void setup()
 +{
 +    sut = new ObjectUnderTest();​
 +}
 +@Test // alle Methoden, die als Test markiert sind, führt JUnit automatisch aus
 +public void test
 +{
 +   ​assertThat(sut.calculate(),​ is(1));
 +}</​code>​
 +
 +Die zentrale Aufgabe beim Schreiben von Tests ist, sich zu überlegen, welche Fälle getestet werden sollen/​müssen.
 +Beispiel: ''​int add(int z1, int z2)''​ -> zu testen sind mindestens alle Kombinationen aus [positiven Zahlen, negativen
 +Zahlen, Null, Integer.MAX,​ Integer.MIN,​ MAX+1, MIN-1, +1, -1]
 +Das ergibt mindestens 81 Kombinationen,​ damit die Methode erschöpfend getestet ist. Das ist in der Praxis so nicht durchführbar.
 +Die Menge an Testfällen muss also der Situation angepasst werden. So wird ein Raketeningenieur in einem überlebenswichtigen System sicherlich mehr Tests für die ''​add''​-Methode implementieren als Informatikstudenten in einer Übungsaufgabe.
 +Eine interessante Vorgehensweise beim Testen ist das **Test Driven Development**:​ Man schreibt zuerst einen Test und
 +erst danach den Code, der den Test erfüllt. Dabei kann man sich von Eclipse den zu testenden Code generieren lassen, um
 +sich Schreibarbeit zu sparen.
 +**Wichtig: Jeder neu geschriebene Test muss am Anfang fehlschlagen,​ um sicherzugehen,​ dass der Test nicht immer positiv ist!**
 +
 +==== Wie finde ich Testfälle? ====
 +  - Anfangen mit dem einfachsten Fall, zB. leerer String, 0, etc.
 +  - Danach mit dem nächst schwierigeren Testfall weitermachen,​ z.B. String bestehend aus einem Buchstaben usw.
 +  - Grenzfälle sollten unbedingt getestet werden (z.B. -1, +1, 0, MIN, MAX, MIN - 1,  MAX + 1, NULL usw.)
 +
 +
 +===== Programmierprinzipien und -tipps =====
 +  * DRY (**Don'​t repeat yourself**):​ Doppelter Code soll vermieden werden, da bei Anpassungen sonst mehrere Stellen aktualisiert werden müssen, was sehr fehleranfällig ist (z.B. wenn eine Stelle übersehen wird).
 +  * Es gibt nicht nur eine richtige Lösung, sondern immer mehrere Lösungsmöglichkeiten. Es gibt zwar Richtlinien,​ aber jeder Entwickler hat seinen eigenen Stil und somit gibt es verschiedene Herangehensweisen und Lösungen.
 +  * Aufgaben sollen nicht stumpf (z.B. anhand einer vorgegebenen Aufgabenstellung) abgearbeitet werden. Vielmehr muss stets untersucht werden, ob es eine einfachere Lösung gibt! (Beispiel Quadratzahlen -> nicht mit den Quadraten anfangen und die Wurzeln ziehen, sondern die Zahlen quadrieren)
 +  * **Single Responsibility Principle** (SRP): Dieses Prinzip besagt, dass jede Klasse/​Methode/​Variable etc. nur eine fest definierte Aufgabe erfüllen soll. Dies soll u.a. helfen bei anfallenden Fehlern die Fehlerquelle schneller bestimmen zu können und macht Anpassungen einfacher umsetzbar.
 +  * Vorgehen beim Programmieren (**divide and conquer**)
 +    * aktuelle **abstrakte** Aufgabe in nächst kleinere/​einfachere (**konkretere**) Teilschritte runterbrechen (= divide)
 +    * wenn Teilschritt implementierbar,​ "​übersetzen"​ in Quelltext: Es ist in der Regel leichter, Lösungen (= conquer) für diese kleinen Aufgaben zu finden und diese später zusammenzufügen,​ als das Eingangsproblem auf Anhieb zu lösen.
 +    * Am Beispiel FizzBuzz kann man das Aufteilen der Aufgabe so angehen:
 +      - 1. Zählen von 1 - 100
 +      - Für alle Zahlen teilbar durch 5 und 3 setze FizzBuzz
 +      - Für alle Zahlen teilbar durch 5 setze Buzz
 +      - Für alle Zahlen teilbar durch 3 setze Fizz
 +      - Redundanzen (z.B. 15 = FizzBuzz, Buzz und Fizz) entfernen
 +      - Zwischen jedem dieser Schritte prüfen, ob das Teilergebnis ein Fortschritt ist.
 +
 +  * YAGNI (**You ain't gonna need it**): Was nicht unbedingt gebraucht wird, wird auch nicht implementiert. Ansonsten handelt man sich ggfs. unnötige Komplexität ein, die spätere Anpassungen erschweren.
 +
 +===== Refactoring =====
 +In der Programmierung ist es wichtig, in Hinsicht auf zukünftige und noch nicht vorhersehbare Änderungen am Programm, den Code so variabel wie möglich zu erstellen, sodass er sich in Zukunft ohne großen Aufwand abändern lässt. ​
 +In diesem Zusammenhang führt man häufig das sog. **Refactoring** durch, eine **semantikinvariante Modifikation** des Quelltexts.
 +Refactoring ist somit eine manuelle oder automatisierte Strukturverbesserung von Programm-Quelltexten unter Beibehaltung des beobachtbaren Programmverhaltens. ​
 +Dabei sollen die Lesbarkeit, Verständlichkeit,​ Wartbarkeit und Erweiterbarkeit verbessert werden, mit dem Ziel, den jeweiligen Aufwand für Fehleranalyse und funktionale Erweiterungen deutlich zu senken.
 +Eine zentrale Voraussetzung für ein "​sicheres"​ Refactoring ohne das Verhalten des Codes zu ändern sind automatische Tests.
 +
 +==== Extract Method ====
 +Eclipse bietet die Möglichkeit,​ durch Markieren eines Codeabschnittes diesen automatisch in eine separate Methode auszulagern. ​
 +Dies funktioniert durch Markieren des gewünschten Abschnittes mit der rechten Maustaste und Auswahl von ''​Refactor > Extract Method''​. ​
 +Es öffnet sich ein Fenster, in dem ein Name für die neue Methode eingegeben werden kann.
 +Die Variablen, die in der Methode Verwendung finden, erkennt Eclipse selbstständig. ​
 +Durch bestätigen des Vorgangs implementiert Eclipse im Code selbstständig eine neue Methode.
 +
 +===== Debugging =====
 +Eclipse stellt uns im System einen **Debugger** zur Verfügung. Dies ist ein Tool, mit dem der Code Schritt für Schritt ausgeführt werden kann, um ihn nach Fehlern zu durchsuchen.
 +Um in Eclipse den Debugger nutzen zu können, muss zunächst ein **Breakpoint** im Code gesetzt werden. ​
 +Ein Breakpoint ist ein Haltepunkt im Code, bei dessen Erreichen im Programmablauf das Programm angehalten wird, sodass die nächsten Schritte einzeln nachvollzogen werden können. ​
 +Ein Breakpoint wird in Eclipse gesetzt, indem mit der rechten Maustaste am Seitenrand "​Toggle Breakpoint"​ ausgewählt wird. 
 +Um zu sehen was passiert, muss die Perspektive auf "​Debug"​ geändert werden.
 +In dieser Perspektive werden zusätzliche Views bereitgestellt,​ die z.B. die aktuell verwendeten Variablen und ihren jeweiligen Inhalt anzeigen.
 +
 +===== Mögliche Klausurfragen =====
 +aus \cite{Lau2011b}
 +  * Was ist eine Programmiersprache?​
 +    * Eine Programmiersprache ist eine formale Sprache mit der ein Programm geschrieben werden kann. Dabei werden dem Computer Anweisungen übergeben, die verarbeitet werden. Der Code kann in Maschinensprache oder in Form von Quelltext geschrieben werden, der dann in Maschinensprache übersetzt wird. Die Bausteine einer Programmiersprache sind das Vokabular (z.B. ''​System.out.println()'',​ die Grammatik (z.B. Verschachtelung von Blöcken) und die Syntax (z.B. Semikolons am Zeilenende).
 +  * Was ist Assembler?
 +    * Ein Assembler ist ein Programm, dass maschinennahe Assemblersprache in Maschinensprache übersetzt. Die Assemblersprache wird von der CPU benutzt und mit der Assemblersprache kann direkt auf Ressourcen wie die CPU bzw. auf deren Speicher oder auf die Grafikkarte zugegrifen werden.
 +  * Was ist eine Hochsprache?​
 +    * Eine Hochsprache ist eine Programmiersprache,​ die der menschlichen Sprache entfernt ähnelt. Die Hochsprache kann der Mensch verstehen und sie ist oft an den Denkgewohnheiten des Menschen angepasst und ist dabei zum größten Teil maschinenunabhängig.
 +  * Was ist ein Parser?
 +    * Ein Parser Überprüft die Syntax einer Eingabe auf Richtigkeit anhand syntaktischer Regeln.
 +  * Was ist ein Compiler und ein Interpreter?​
 +    * Eine Compiler-Sprache wird vor der Ausführung in Maschinencode (bzw. Bytecode bei Java) übersetzt. Zur Übersetzung wird der Compiler benötigt.
 +    * Eine Interpreter-Sprache wird zur Laufzeit durch einen Interpreter Befehl für Befehl übersetzt und direkt ausgeführt.
 +  * Was ist ein JIT-Compiler?​
 +    * Der Just-In-Time Compiler kompiliert ähnlich wie bei der Interpreter-Sprache zur Laufzeit. Jedoch werden die kompilierten Daten im Cache abgelegt, sodass diese nicht erneut übersetzt werden müssen wie beim Interpreter.  ​
 +  * Was ist Bytecode?
 +    * In manchen Programmiersprachen wird nicht direkt in Maschinensprache übersetzt, sondern in einen Zwischencode,​ der Bytecode genannt wird. Dieser ist oftmals plattformunabhängig.
 +  * Was heißt "​statisch typisiert"​ und "​dynamisch typisiert"?​
 +    * Bei der statischen Typisierung wird der Datentyp von Variablen bereits während der Kompilierung festgelegt. Bei der dynamischen Typisierung wird kein spezieller Datentyp definiert. Der Typ ergibt sich aus dem ihr zugewiesenen Wert und kann sich zur Laufzeit ändern.
 +  * Was heißt "stark typisiert"?​
 +    * Bei starker Typisierung können Datentypen nicht verändert (siehe Cast) werden. Durch die starke Typisierung sollen Fehler zur Laufzeit verhindert werden. Hier ist es wichtig, dass die möglichen Eingabewerte so eingeschränkt werden, dass kein Fehler entstehen kann.
 +  * Was sind mögliche Vorteile von statischer Typisierung?​
 +    * Fehler können bereits bei der Übersetzung gefunden werden und nicht erst zur Laufzeit. Die Eingabewerte müssen richtig sein. Die Performance wird gesteigert, da zur Laufzeit keine Überprüfung des Datentyps mehr erforderlich ist.
 +  * Was sind mögliche Vorteile von dynamischer Typisierung?​
 +    * Ist einfacher für den Programmierer,​ da die einzelnen Methoden nicht für jeden Datentyp definiert werden müssen.
 +  * Was ist strukturierte und prozedurale Programmierung?​
 +    * Bei der strukturierten Programmierung beschränkt man sich in unterster Ebene auf drei Kontrollstrukturen (siehe Algorithmus). Bei der prozeduralen Programmierung werden zusätzlich eigene Funktionen und Prozeduren definiert. Dabei geben Funktionen einen Rückgabewert zurück und Prozeduren geben keinen Wert zurück.
 +  * Was bedeutet "​deterministisch"?​
 +    * Deterministisch bedeutet, dass ein Computer ein Programm immer gleich ausführt und das grundsätzlich das gleiche Ergebnis zu erwarten ist.
 +  * Was ist ein Register?
 +    * Ein Speicherbereich der direkt mit der CPU verbunden ist und auf den die CPU zugreifen kann. Über diesen werden Berechnungen durchgeführt.
 +  * Was ist der Stack?
 +    * Ein Stapel der bei jedem Funktionsaufruf aufgebaut wird. Dabei wird nach dem LiFo-Prizip gearbeitet, sodass ein neuer Funktionsaufruf immer oben auf den Stapel gelegt wird. Nach der Abarbeitung,​ wird der nächste Aufruf des Stapel bearbeitet. ​
 +  * Was sind Stack und Heap?
 +    * Der Stack ist ein Stapel, der nach dem LiFo-Prinzip abgebaut wird. Der Heap ist der Großteil des Arbeitsspeichers,​ in dem die Daten zur Laufzeit verarbeitet werden.
 +  * Was ist ein Pointer/​Zeiger?​
 +    * Ein Pointer zeigt auf eine Adresse im Adressspeicher.
 +
 +aus \cite{Krypczyk2011c}
 +  * Was ist eine Bibliothek?
 +    * Eine Sammlung an Funktionen, die innerhalb einer Programmiersprache verwendet werden können (z.B. ''​Math''​ in Java). ​
 +  * Was ist eine DLL?
 +    * DLL = Dynamic Link Library; Bezeichnet eine Bibliothek, die überlicherweise bei Microsoft Anwendung findet.
 +  * Welche Arten von Fehlern gibt es bei der Programmierung von Algorithmen?​
 +    * Eingabefehler,​ Verfahrensfehler,​ Fortpflanzungsfehler,​ Rechenfehler
 +  * Wie geht man beim Entwickeln von Algorithmen vor?
 +    * Der Algorithmus muss in kleine Teilschritte zerlegt werden. Diese Teilschritte können dann nach und nach niedergeschrieben werden.
 +
  
phwt/skriptjava.txt · Zuletzt geändert: 2015-01-04 19:12 (Externe Bearbeitung)