Während Ihr darauf wartet, dass es beginnt..
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
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
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.
- Deklariere ein Interface
Form
, das eine Methode float getFlaeche()
fordert.
- Implementiere das Interface für 2 Klassen:
Rechteck
und Dreieck
(Konstruktoren, implements
, float getFlaeche()
)
- 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);
…
- Ü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)
- Lasse die beiden Klassen
Rechteck
und Dreieck
das Comparable<Form>
-Interface implementieren. Vergleiche in der Methode int compareTo(Form f)
die Flächen entsprechend.
- Lege einen Array
Form[] formen
von den vier Objekten an (= {r1,r2,d1,d2}
).
- Wir brauchen die
Arrays
-Klasse für den nächsten Schritt: import java.util.Arrays;
- Gib
formen
aus, indem du Arrays.toString(formen)
verwendest.
- Nutze
Arrays.sort(formen)
, um das Array zu sortieren.
- 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!
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
Quellen
Inspiration für Probleme: