EINFÜHRUNG IN DIE PROGRAMMIERUNG FORTGESCHRITTENE KONZEPTE Tobias Witt 26.03.2014 • [email protected] • 25.12.01.30 • Bürozeiten: 09 Uhr - 12 Uhr FEHLERBEHANDLUNG KLASSISCHER ANSATZ • Fehlercode als Rückgabewert von Methoden ‣ String ➜ Fehlercode als String ‣ int ➜ Fehlercode als Integer ‣ List ➜ ??? ‣ void ➜ ??? KLASSISCHER ANSATZ PROBLEME • Fehlerbehandlung stets direkt • Abfrage von Rückgabewert nötig ‣ Verschiedene Fehler - verschiedene FehlerRückgabewerte • Einschränkung des Werte-Bereichs der Methode AUSNAHMEN - EXCEPTIONS • Fehler als „Ausnahme“ explizit oder implizit ausgelöst • Fehlerursache „wirft“ Exception • Fehlerbehandler „fängt“ Exception AUSNAHMEN - EXCEPTIONS • Geprüfte Ausnahmen (Checked Exceptions) ‣ • Ungeprüfte Ausnahmen (Unchecked Exceptions) ‣ • Müssen behandelt werden Müssen nicht unbedingt behandelt werden Jede nicht behandelte Exception bricht das Programm ab! AUSNAHMEN BEISPIELE NullPointerException Methode wird auf null aufgerufen ArrayIndexOutOfBoundsException Zugri# auf nicht existierenden Array-Index ClassCastException Casting nicht möglich NumberFormatException z.B. bei Integer.parseInt("bogus") FileNotFoundException Dateiname existiert nicht Exception KLASSE • Geprüfte Exceptions: ‣ • Erben von Exception Ungeprüfte Exceptions: ‣ Erben von RuntimeException AUSNAHMEN BEHANDELN Ungeprüfte NumberFormatException public class Spiel { public static void main(String[] args) { int a = Integer.parseInt("42"); FileInputStream f = new FileInputStream("datei"); } } Unhandled exception: java.io.FileNotFoundException AUSNAHMEN BEHANDELN public class Spiel { public static void main(String[] args) { FileInputStream f; try { f = new FileInputStream("datei"); } catch (FileNotFoundException e) { f = createFile("datei"); } } } AUSNAHMEN BEHANDELN public class Spiel { public static void main(String[] args) { try { FileInputStream f = new FileInputStream("datei"); int firstByte = f.read(); } catch (FileNotFoundException e) { e.printStackTrace(); } Unhandled exception: java.io.IOException } } AUSNAHMEN BEHANDELN public class Spiel { public static void main(String[] args) { try { FileInputStream f = new FileInputStream("datei"); int firstByte = f.read(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace() } } } AUSNAHMEN BEHANDELN public class Spiel { public static void main(String[] args) { try { FileInputStream f = new FileInputStream("datei"); int firstByte = f.read(); } catch (FileNotFoundException | IOException e) { e.printStackTrace(); } } } AUSNAHMEN BEHANDELN public class Spiel { public static void main(String[] args) { try { FileInputStream f = new FileInputStream("datei"); // ... } catch (Exception e) { } finally { f.close(); } } Unhandled exception: java.io.IOException } AUSNAHMEN BEHANDELN try with resources (Java 7) public class Spiel { public static void main(String[] args) { try (FileInputStream f = new FileInputStream("datei")) { // ... } catch (Exception e) { implements AutoClosable } } } AUSNAHMEN BEHANDELN II public class LevelDatei implements AutoCloseable { private File levelDatei; public LevelDatei(String fileName) throws IOException { levelDatei = createFile(fileName); } private File createFile(String fileName) throws IOException { // erstelle Datei } public void schreibeLevel() throws IOException { // schreibe Level in Datei } @Override public void close() throws Exception { // schließe Datei } } AUSNAHMEN BEHANDELN II public class Spiel { public static void main(String[] args) { try(LevelDatei ld = new LevelDatei("level1.lvl")) { ld.schreibeLevel(); } catch (IOException) { e.printStackTrace(); } } } AUSNAHMEN ERZEUGEN public class Wurm { public class WurmLebenException extends IllegalArgumentException { } private int leben; public Wurm(int leben) { if (leben <= 0) { throw new WurmLebenException( "Leben muss größer 0 sein"); } this.leben = leben; } } NEBENLÄUFIGKEIT MAIN THREAD Start • main-Methode im Main Thread • Sequentielle Ausführung innerhalb jedes Threads • Anweisungen blockieren & warten Anweisung 1 Anweisung 2 Anweisung 3 Ende MEHRERE THREADS • • • Asynchrone Ausführung von Main Thread und Thread 2 Gefahr bei Verwendung gleicher Daten Anweisungen blockieren & warten nur innerhalb eines Threads Main Thread Start Thread 2 Anweisung 1 Start Anweisung 2 Anweisung 4 Anweisung 3 Ende Anweisung 5 Ende THREADS STARTEN public class Spiel { public static void main(String[] args) { final String string = " du"; Thread t = new Thread(new Runnable() { @Override Closure public void run() { try { „main-Methode“ des Threads Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(string); } }); t.start(); System.out.print("Hallo"); } } JAVA 8 public class Spiel { public static void main(String[] args) { final String string = " du"; Thread t = new Thread(()-> { Lambdatry { Expression Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(string); }); t.start(); System.out.print("Hallo"); } } ERGEBNIS? Main Thread Start Thread 2 Starte Thread $ java Spiel Hallo du Gebe “Hallo“ aus Ende Start Warte 2s Gebe “ du“ aus Ende TIMING-PROBLEME Korrektes Ergebnis? public class Spiel { public static void main(String[] args) { DatenDownloader dd = new DatenDownloader(); dd.starteLangenDownloadAsynchron(); String ergebnis = dd.getErgebnis(); } } TIMING-PROBLEME Lösung? NEIN!!!!! public class Spiel { public static void main(String[] args) { DatenDownloader dd = new DatenDownloader(); dd.starteLangenDownloadAsynchron(); Thread.sleep(2000); String ergebnis = dd.getErgebnis(); } } CALLBACK public interface DownloadListener { public void fertig(String ergebnis); } public class DatenDownloader { public void starteLangenDownload(DownloadListener l) { new Thread(() -> { // download... String ergebnis = "ergebnis"; l.fertig(ergebnis); }).start(); } } CALLBACK IMPLEMENTIEREN public class Spiel { public static void main(String[] args) { DatenDownloader dd = new DatenDownloader(); dd.starteLangenDownload(new DownloadListener() { @Override public void fertig(String ergebnis) { // verarbeite ergebnis } }); } } JAVA 8 LambdaExpression mit Parameter public class Spiel { public static void main(String[] args) { DatenDownloader dd = new DatenDownloader(); dd.starteLangenDownload((String ergebnis) -> { // verarbeite ergebnis }); } } GEMEINSAM GENUTZTE DATEN • • Thread 1 Thread 2 Start Start konto1 -= 9 konto1 -= 2 konto2 += 9 konto2 += 2 Ende Ende konto1 = 10 konto2 = 0 public class Spiel { static int konto1 = 10; static int konto2 = 0; static void transfer(int betrag) { if (konto1 - betrag >= 0) { // Zeit vergeht konto1 -= betrag; konto2 += betrag; } } public static void main(String[] args) { new Thread(() -> { transfer(2); }).start(); new Thread(() -> { transfer(9); }).start(); } } MÖGLICHE ERGEBNISSE Gültig konto1 = 1, konto2 = 9 Gültig konto1 = 8, konto2 = 2 Ungültig konto1 = -1, konto2 = 11 public class Spiel { static int konto1 = 10; static int konto2 = 0; static void transfer(int betrag) { if (konto1 - betrag >= 0) { // Zeit vergeht konto1 -= betrag; konto2 += betrag; } } public static void main(String[] args) { new Thread(() -> { transfer(2); }).start(); new Thread(() -> { transfer(9); }).start(); } } public class Spiel { static int konto1 = 10; static int konto2 = 0; Spiel während Methode gesperrt synchronized static void transfer(int betrag) { if (konto1 - betrag >= 0) { // Zeit vergeht konto1 -= betrag; konto2 += betrag; } } public static void main(String[] args) { new Thread(() -> { transfer(2); }).start(); new Thread(() -> { transfer(9); }).start(); } } DEADLOCK DEADLOCK Thread 1 Thread 2 Sperre auf a Sperre auf b Sperre auf b Sperre auf a Entferne Sperre auf a Entferne Sperre auf b Entferne Sperre auf b Entferne Sperre auf a TEST DRIVEN DEVELOPMENT TDD • Software in ständiger Metamorphose • Tests zwingend erforderlich ‣ • Egal ob von Menschen oder automatisch Test Driven Development: Tests vor der Implementierung implementieren BOWLING GAME KATA 1 4 5 4 5 14 6 5 29 0 49 60 1 61 7 6 77 2 97 117 6 133 • 10 Frames • Spare: 10 Pins in 2 Würfen: Nächster Wurf doppelt • Strike: 10 Pins in 1 Wurf: Nächsten 2 Würfe doppelt • Strike oder Spare im letzten Frame: 1-2 Würfe extra ANFORDERUNGEN • Game Klasse ‣ public void roll(int pins); - ‣ Simuliert einen Wurf public int score(); - Gibt die Gesamtpunktzahl zurück BEGINN • • Erstelle neues Projekt ‣ File ➜ New Project ➜ Java ‣ Name: BowlingGame Erstelle GameTest Klasse ‣ Rechtsklick auf src ➜ New ➜ Java Class ‣ Name: de.hhu.propra.bowlinggame.GameTest BILDQUELLEN Bild Quelle Exceptions, Threads http://geek-and-poke.com/ Deadlock http://openbook.galileocomputing.de/javainsel9/bilder/ 365_java_09_004.gif TDD http://www.projectcartoon.com/cartoon/353819