11th Java Lesson (Java Course @ TUD)

https://github.com/Trivo25/tud-java-course

January 13, 2022

Während Ihr darauf wartet, dass es beginnt..

Java

Objektorientierte Programmierung

Florian Kluge, Moritz Schulz

  1. January 2022

https://trivo25.github.io/tud-java-course/


Florian.Kluge@mailbox.tu-dresden.de

Moritz.Schulz2@mailbox.tu-dresden.de

Was wir heute machen

Fehler und erweiterte Datentypen

  • Wiederholung Interfaces
  • Zeit für die letzte Aufgabe & Besprechung
  • Exceptions & Error Handling
  • aus Standard Library: ArrayList, HashMap

Contact

Florian Kluge

Florian.Kluge@mailbox.tu-dresden.de

Moritz Schulz

Moritz.Schulz2@mailbox.tu-dresden.de

Kurze Info zum Kurs: online

  • bitte abmelden / entschuldigen, wenn ihr nicht kommt
    • zwei Mal in Folge unentschuldigt fehlen => ausgetragen
  • bitte, fragt gern, jederzeit
    • entweder Frage im Chat stellen
    • oder sich mit Handzeichen melden => nach dem Drannehmen per Mikro die Frage stellen
  • praktische Aufgaben- und Beispiel-basierte Lernweise
    • wenn ihr nicht weiterkommt / sich etwas komisch verhält:
      • “?” in den Chat schreiben
      • wir gehen mit dir in einen Breakout-Raum
      • du kannst dann den Bildschirm teilen
  • uns geht es darum, alle mitzunehmen

Stay up to date

  • die E-Mails der TUD regelmäßig überprüfen
    • z.B. Bekanntgabe der Veröffentlichung der Folien
      • auf der Seite des Programmierkurses

Los geht’s!

Wiederholung Interfaces: Zweck

  • Klassen können mehrere Interfaces implementieren
  • Interfaces geben vor
    • welche Methoden Objekte dieser Klasse haben sollen
    • legen dabei aber kein Standardverhalten fest
  • Klassen setzen Methoden des Interfaces um: @Override

Wiederholung Interfaces: Beispiel

interface Animal {
    public void makeSound();
}

class Pig implements Animal {
    @Override
    public void makeSound() {
        System.out.println("oiinkk");
    }
}


// zum Beispiel in main(String[] args):
    Animal pig1 = new Pig();
    pig1.makeSound(); // 'oiinkk'

15min für die vorige 1. Aufgabe

… danach Besprechung & Beispielcode zeigen

Wer schon fertig ist: Aufgabe 2 durchdenken (in 3 Folien)

Aufgabe 1 zu Interfaces (Teil 1)

Arbeite hier gern mit mehreren Dateien.

  1. Deklariere ein Interface Form, das eine Methode float getFlaeche() fordert.
  2. Implementiere das Interface für 2 Klassen: Rechteck und Dreieck (Konstruktoren, implements, float getFlaeche())
  3. Teste, ob der Code wie gewünscht funktioniert, indem du jeweils zwei Rechtecke und zwei Dreiecke erstellst und deren Fläche in der Konsole ausgeben lässt: System.out.println(flaeche1);
  4. Überschreibe (@Override) die String toString()-Methode in den Klassen, und verwende sie, um auch das Objekt in der Konsole auszugeben

Aufgabe 1 zu Interfaces (Teil 2)

  1. Lasse die beiden Klassen Rechteck und Dreieck das Comparable<Form>-Interface implementieren. Vergleiche in der Methode int compareTo(Form f) die Flächen entsprechend.
  2. Lege einen Array Form[] formen von den vier Objekten an (= {r1,r2,d1,d2}).
  3. Wir brauchen die Arrays-Klasse für den nächsten Schritt: import java.util.Arrays;
  4. Gib formen aus, indem du Arrays.toString(formen) verwendest.
  5. Nutze Arrays.sort(formen), um das Array zu sortieren.
  6. Gib formen auch nach dem Sortiervorgang aus.

Optionale Aufgabe 2 zu Interfaces & Arrays

Setze eine Queue (Warteschlange) von int-Werten als Interface um.

Eine Queue ist ein abstrakter Datentyp nach FIFO-Prinzip: First in, first out. D.h. das Element, das zuerst hinzugefügt wird, wird auch zuerst herausgenommen.

Das Interface hat die Methoden

  • void push(int i): füge einen int hinten an
  • int pop(): entferne den letzten int und gib ihn zurück

Setze dies mit einem Array um. Sollte der Array irgendwann zu klein sein, um noch eine weitere Zahl zu halten, musst du einen neuen Array erstellen und zunächst alle Elemente kopieren.

Teste deine Implementierung mit kleinen und großen Queues.

Errors (Exceptions)

  • Es kann bei Programmausführung zu Fehlern kommen - Dinge gehen schief.
  • Es gibt verschiedene Typen von Laufzeitfehlern
    • logische Fehler (coding errors)
    • Fehler Aufgrund von falschen Input
    • unvorhersehbare Fehler

Error Handling

  • wenn ein Fehler auftritt, “wirft” Java einen Fehler und unterbricht den Programmfluss
  • Fehler kann man auffangen und somit behandeln
  • Fehler werden in die aufrufende Funktion weitergegeben
    • bis sie behandelt werden
    • sonst wird das Programm beendet
  • z.B. in der “Parent”-Funktion auffangen, und in der “Child”-Funktion werfen
public void static main(String[] args) {
    funktionDieFehlerWirft(); // Fehler hier auffangen!
}

// ...

void funktionDieFehlerWirft() {
    // Fehler hier werfen!
}

Error Handling

  • in einem try-Block können wir vorsichtig Code prüfen, ob er Fehler wirft
  • sobald ein Fehler geworfen wird, wird der try-Block abgebrochen
  • mit catch-Block fangen wir mögliche Fehler auf und können damit arbeiten

Error Handling

try {
    // Code welcher Fehler werfen kann
} catch (Exception e) {
    // Fehler auffangen
}

Error Handling

  • Arrays haben eine bestimmte Länge
    • wenn man auf ein Element zureifen will, welcher nicht existiert, entsteht ein Fehler
    • java.lang.ArrayIndexOutOfBoundsException
  • als Resultat stürzt das Programm ab..
public class Main {
  public static void main(String[ ] args) {
    int[] numbers = {1, 2, 3};
    System.out.println(numbers[5]); // Java wirft einen Fehler!

    System.out.println("Ende des Programms");
  }
}

Error Handling

  • wie fängt man so einen Fehler nun auf, ohne dass das Programm abstürzt?
public class Main {
  public static void main(String[ ] args) {
    try {
       int[] numbers = {1, 2, 3};
       System.out.println(numbers[5]); // Java wirft einen Fehler! 
    } catch (Exception e) {
        System.out.println("Irgendwas ist schief gelaufen..");
    }

    System.out.println("Ende des Programms");
  }
}

Error Handling

  • neben try und catch gibt es noch einen finally-Block
  • Code im finally-Block wird immer nach Ende des try-catch-Blocks ausgeführt
public class Main {
  public static void main(String[ ] args) {
    try {
       int[] numbers = {1, 2, 3};
       System.out.println(numbers[5]); // Java wirft einen Fehler! 
    } catch (Exception e) {
        System.out.println("Irgendwas ist schief gelaufen..");
    } finally {
        System.out.println("try-catch Block vorbei");
    }

    System.out.println("Ende des Programms");
  }
}

Error Handling

  • wir können auf selbst Fehler werfen!
  • das throw-Keyword wirft einen Fehler
  • ein Fehler muss immer einen Typ haben
  • Beispiel:
    • ArithmeticException
    • FileNotFoundException
    • ArrayIndexOutOfBoundsException
    • SecurityException
// es wird versucht, eine Datei zu lesen. Dabei kann sie aber nicht gefunden werden!
throw new FileNotFoundException("Die Datei konnte nicht gefunden werden.");

Error Handling

  • Beispiel: Alterüberprüfung
try {
    isOldEnough(14);
} catch (Exception e) {
    System.out.println(e);
}

// ...

static boolean isOldEnough(int age) {
    if(age >= 18) {
        return true;    
    } else {
        throw new ArithmeticException("Nicht alt genug!");
    }
}

Aufgabe zu Error Handling

  • Schreibt eine Funktion float div(int a, int b)
    • welche den Quotienten (Kommazahl) der beiden Zahlen a und b ausrechnet
    • Aber: Sollte die zweite Zahl 0 sein, dann wirft die Funktion einen Fehler: ArithmeticException
  • Ruft div(...) in public static void main(String[] args) auf
  • Fangt den Fehler ab und gebt eine sinnvolle Konsolenausgabe!

Standard-Library und Helfer

https://docs.oracle.com/javase/7/docs/api/

java.util Package

https://docs.oracle.com/javase/7/docs/api/

java.util Package

  • das java.util-Package liefert uns eine Reihe an sehr hilfreichen Klassen

java.util.ArrayList<E>

ArrayList<E> vs Array

  • ganz am Anfang haben wir Arrays kennengelernt
    • Arrays sind Listen von Datentypen mit einer vordefinierten Länge
  • ArrayList<E> machen das gleiche
    • sie haben aber keine vordefinierte Länge - sie sind also dynamisch!

ArrayList<E> vs Array

  • wenn man die Anzahl der Elemente in einem Array ändern will, müsste man immer ein neues Array erstellen
  • ArrayList<E> macht das automatisch - man muss sich also keine Gedanken drüber machen

Was bedeutet <E> ?

  • <E> indiziert, dass die Klasse generisch ist!
    • generisch = die Klasse kann, einfach gesagt, mit unterschiedlichen Datentypen(Klassen) initialisiert werden (ähnlich wie Comparable<T>)
  • Beispiel:
    • ArrayList<String> - ArrayList bestehend aus String-Objekten
    • ArrayList<Integer> - ArrayList aus Integer-Objekten (oder int)
    • ArrayList<MyClass> - ArrayList aus MyClass-Objekten

Wichtig: nicht verrückt werden - einfach so hinnehmen!

Generics werden in der Softwaretechnologie-Vorlesung besprochen

Beispiel ArrayList<E>

// wir müssen die vordefinierte Klasse zunächst importieren!
import java.util.ArrayList; 

// ArrayList vom Datentyp String
ArrayList<String> namen = new ArrayList<String>();

Vergleich Array und ArrayList<E>

// ArrayList vom Datentyp String
ArrayList<String> namen1 = new ArrayList<String>();
    
// vordefinierte Länge von 5
// kann nicht dynamisch länger werden!
String[] namen2 = new String[5];

Vergleich Array und ArrayList<E>

String[] namen2 = new String[5];
// Zugriff auf Position 2; Index 2!
namen2[2] = "Max Mustermann"; 

ArrayList<String> namen1 = new ArrayList<String>();
// Zugriff auf Position 2; Index 2! ABER: mit .set(i, s);
namen1.set(2, "Max Mustermann");

Methoden von ArrayList<E>

weitere Methoden um mit ArrayList<E> zu arbeiten

ArrayList<String> namen = new ArrayList<String>();
// .get(i) - gibt Wert an Position i zurück
// kann java.lang.IndexOutOfBoundsException werfen
namen.get(0); // "Max Mustermann"
// .set(i, s) - setzt Wert s an Position i 
// kann java.lang.IndexOutOfBoundsException werfen
namen.set(0, "Max Mustermann");
// .add(s) - fügt Element s hinten an Liste an
namen.add("Mustermann Max");
// .remove(i) - entfernt Element an Position i;
//              Elemente danach "rutschen nach"
namen.remove(0);
// .clear() - entfernt alle Elemente
namen.clear();
// .size() - gibt die Anzahl der Elemente zurück
namen.size();

Schleifen ArrayList<E>

ArrayList<String> namen = new ArrayList<String>();

for (int i = 0; i < namen.size(); i++) {
    // indirekter Zugriff via index
    System.out.println(namen.get(i));
}

Schleifen ArrayList<E>

ArrayList<String> namen = new ArrayList<String>();

for (String name : namen) {
    // direkter Zugriff
    System.out.println(name);
}
  • Achtung: java.util.ConcurrentModificationException bei Veränderung der ArrayList innerhalb von for
    • dabei also lieber die vorige for-Schleife

Aufgabe #1 zu ArrayList<E>

  • Erstellt eine ArrayList<Integer> mit dem Namen vielfache.
  • Nutzt eine Schleife um alle Vielfache von 5 von 0 bis 100 der ArrayList<E> vielfache hinzuzufügen.
// 3 (von 4) Arten von Schleifen in Java
for (int i = 0; i < 42; i++) {} // i ∈ {0, ..., 41}
for (int i : arrayOfInts) {} // i ∈ arrayOfInts
while (bedingung) {}

Aufgabe #2 zu ArrayList<E>

Implementiert den Algorithmus “Sieb des Eratosthenes” mit einer ArrayList<Integer> primzahlen!

  • Füllt sie dazu zunächst mit den Zahlen 2 bis 100.
  • Entfernt gemäß Algorithmus alle nicht-Primzahlen zwischen 2 bis 100
  • In primzahlen verbleiben nur Primzahlen. Gebt diese dann aus.
  • Algorithmus: [Sieb des Eratosthenes](https://de.wikipedia.org/wiki/Sieb_des_Eratosthenes):
    • Man notiert sich die Zahlen 2 bis n
    • Wiederhole, solange wie die Liste noch nicht abgearbeitet ist
      • Sei i die nächste Zahl in der Liste (zu Beginn 2)
      • i in der Liste belassen (i ist prim)
      • alle Mehrfachen von i (also 2 i, 3 i, \dots) aus der Liste entfernen
  • Hinweise und Erweiterung auf der nächsten Seite

Aufgabe #2 zu ArrayList<E> - Hinweise & Erweiterung

  • Aufpassen: java.lang.IndexOutOfBoundsException - die Liste wird kürzer
  • Aufpassen: Wenn Elemente aus der Liste entfernt werden, ändert sich ihr Index
    • Tipp: vom größten Index begonnen abarbeiten
  • Erweiterung: Als Funktion schreiben
    • die die ArrayList zurückgibt
    • die Primzahlen bis zum Parameter int n berechnet

Aufgabe #3 zu ArrayList<E>

  • erstellt eine ArrayList<E> vom Typ Integer mit dem Namen teilerfremde
  • fügt alle teilerfremden Zahlen zu 18 von 0 bis 100 der ArrayList teilerfremde hinzu
  • am Ende werden alle Zahlen in der Liste teilerfremde summiert
  • gegeben ist die Funktion int ggt(a, b)

Hinweis: a ist teilerfremd zu 18 wenn ggt(a, 18) == 1

static int ggt(int a, int b) {
  int h = (a > b) ? b : a;

  for (int i = h; i > 1; i--) {
    if ((a % i) == 0 && (b % i) == 0) {
      return i;
    }
  }
  return 1;
}

Kurze Anmerkung

  • wir haben heute mit Generics gearbeitet, aber diese nicht genauer betrachtet

See course materials here: https://trivo25.github.io/tud-java-course/

Check out the Cheat Sheet: http://tiny.cc/java-cs

Quellen

Inspiration für Probleme: