Programmieren in Java

Werbung
Programmieren in Java
Stephan Fischli
Winter 2016/17
Inhalt
●
Einführung
●
Datentypen
●
Klassen und Objekte
●
Enumerations
●
Packages
●
Vererbung
●
Interfaces
●
Innere Klassen
●
Standardbibliothek
●
Exception‐Handling
●
Collections
●
Generics
●
Threading
Einführung
Warum Java?
Einführung
●
Einfachheit und Robustheit der Sprache
●
Plattformunabhängigkeit (write once – run everwhere)
●
Vielseitigkeit der Anwendungen
●
Grosse Verbreitung
6
Java‐Plattform
●
●
●
●
●
Sprache
Laufzeitumgebung
Virtuelle Maschine (JVM), Garbage Collector, Hotspot‐Compiler
Standardbibliothek
Collections, Ein‐/Ausgabe, GUI, Datenbanken, Networking, ...
Tools
Compiler, Interpreter, Dokumentation, ...
Editionen
Standard (Java SE), Enterprise (Java EE), Micro (Java ME)
Einführung
7
Java‐Architektur
Java Sourcecode
Java Compiler
Java Bytecode
Java Virtual Machine (JVM)
Betriebssystem
Hardware
Einführung
8
Entwicklungszyklus
●
●
●
Implementierung in Datei Hello.java
public class Hello {
public static void main(String[] args) {
System.out.println("Hello " + (args.length > 0 ? args[0] : "world"));
}
}
Kompilation erzeugt Datei Hello.class
C:\> javac Hello.java
Ausführung der Klasse
C:\> java Hello John
Einführung
9
Geschichte von Java
Jahr
1995
1997
1998
2000
2002
2004
2006
2011
2014
2016
Einführung
Version
JDK 1.0
JDK 1.1
J2SE 1.2
J2SE 1.3
J2SE 1.4
J2SE 5
Java SE 6
Java SE 7
Java SE 8
Java SE 9
Features
Erste Version
Innere Klassen, Reflection, Datenbanken
Collections, Swing
HotSpot‐Compiler
Asserts, reguläre Ausdrücke, neue I/O‐Bibliothek
Generics, Annotationen, Enums, Concurrency Utilities
Web Services
Schliessen von Ressourcen, Multicatch von Exceptions
Lambda‐Expressions, Streams
Modulsystem
10
Java‐Community
●
●
●
Java Community Process (JCP)
Prozess zur Entwicklung neuer Java‐Spezifikationen
https://jcp.org/en/home/index
Java Specification Request (JSR)
Vorschläge für Erweiterungen der Java‐Plattform
https://jcp.org/en/jsr/overview
OpenJDK
Open‐Source Entwicklung der Java‐Plattfom
http://openjdk.java.net/
Einführung
11
Literatur
●
●
●
Einführung
The Java Tutorial
Raymond Gallardo et.al. (Addison‐Wesley)
Effective Java
Joshua Bloch (CreateSpace)
Einführung in Java
Kai Günster (Rheinwerk)
12
Datentypen
Primitive Typen
Primitive Typen
●
repräsentieren Zahlen (byte, short, int, long, float, double), Zeichen (char) oder Wahrheitswerte (boolean)
●
haben eine festgelegte Speichergrösse und Wertebereich
●
können implizit oder explizit ineinander umgewandelt werden (Cast)
●
●
erlauben bestimmte Operationen (Rechnen, Vergleiche, Bit‐
Manipulationen, Logische Verknüpfungen)
haben Wertsemantik
int a = 42;
int b = a;
int c;
Datentypen
a
42
b
42
c
0
14
Objekttypen
Objekttypen
●
repräsentieren Objekte und Arrays
●
haben Referenzsemantik
●
können null sein
Account a = new Account("John", "12345", 1000.0);
Account b = a;
Account c;
a
John
12345
b
c
1000.0
null
Datentypen
15
Referenzsemantik
●
●
●
Datentypen
Nach Zuweisungen zeigen Referenzen auf dasselbe Objekt
a.customer = "Mary";
System.out.println(b.customer);
System.out.println(c.customer);
Bei der Parameterübergabe werden Referenzen übergeben
void deposit(Account x, double amount) { x.balance += amount; }
deposit(a, 200.0);
System.out.println(a.balance);
Bei Vergleichen werden Referenzen verglichen
System.out.println(a == b);
System.out.println(a == c);
16
Wrapper‐Klassen
Wrapper‐Klassen (Byte, Short, Integer, Long, Float, Double, Character, Boolean)
●
repräsentieren Objekte, die einen primitiven Typ enthalten ●
haben zusätzliche Funktionalität (z.B. Parsen von Strings)
●
können explizit oder implizit umgewandelt werden
Integer A = Integer.valueOf(42);
int a = A.intValue();
Integer A = 42;
int a = A;
A
a
// Autoboxing
// Unboxing
42
42
Datentypen
17
Arrays
Arrays
●
enthalten eine feste Anzahl primitiver Werte oder Objekte eines Typs
●
werden vor ihrer Verwendung deklariert, konstruiert und initialisiert
●
kennen ihre Länge (Attribut length)
Account[] a = new Account[5];
a[0] = new Account("John", "12345", 1000.0);
for (int i = 0; i < a.length; i++)
System.out.println(a[i].getCustomer());
a
John
null
12345
null
1000.0
null
null
Datentypen
18
Strings
Strings
●
sind Zeichenketten, die als Objekte der Klasse String repräsentiert werden
●
können nicht verändert werden (immutable)
●
können mit dem Operator + konkateniert werden
String copyright = "\u00a9 Copyright by ...";
if ("nobody".equals(myName)) ...
Sytem.out.println("Server startup time: " + time + " ms");
Datentypen
19
Klassen und Objekte
Definition einer Klasse
●
Eine Klasse definiert einen Datentyp bestehend aus Feldern (Daten) und Methoden (Funktionen), welche auf die Felder zugreifen
pubic class Account {
// Felder
String customer;
String pin;
double balance = 0.0;
}
Klassen und Objekte
// Methoden
void deposit(double amount) {
balance += amount;
}
void withdraw(double amount) {
balance -= amount;
}
Account
customer
pin
balance
deposit()
withdraw()
22
Erzeugen von Objekten
●
Objekte einer Klasse werden mit dem new‐Operator erzeugt
●
Jedes Objekt erhält eine eigene Kopie der Felder
●
Über die Objektreferenz kann auf die Felder und Methoden des Objekts zugegriffen werden
Account a = new Account();
a: Account
a.customer = "John";
a.pin = "12345";
a.balance = 1000.0;
customer="John"
pin="12345"
balance=1200.0
a.deposit(200.0);
Klassen und Objekte
23
Zugriffsrechte von Feldern und Methoden
●
●
Private Felder sind nur innerhalb der Klasse zugreifbar (Daten‐
kapselung), ebenso private Methoden
Public Felder und Methoden sind von überall aus zugreifbar
public class Account {
private String customer;
private String pin;
private String balance = 0.0;
public String getCustomer() { return customer; }
public double getBalance() { return balance; }
}
public void deposit(double amount) { ... }
public void withdraw(double amount) { ... }
Account a = new Account();
a.balance = 1000.0;
Klassen und Objekte
// Selektoren
// Modifikatoren
// Fehler
24
Initialisieren von Objekten
●
●
Konstruktoren werden implizit bei der Erzeugung eines Objekts aufgerufen und dienen der Initialisierung der Felder
Wird kein Konstruktor definiert, so erzeugt der Compiler einen Defaultkonstruktor, der die Felder mit Defaultwerten initialisiert
public class Account {
private String customer;
private String pin;
private double balance = 0.0;
}
public Account(String name, String code) {
customer = name;
pin = code;
}
...
// Konstruktor
Account a = new Account("John", "12345");
Klassen und Objekte
25
Überladen von Methoden
●
●
Mehrere Methoden können denselben Namen haben, sofern sie sich in den Parametern unterscheiden
Bei einem Aufruf entscheidet der Compiler anhand der Argumente, welche Methode ausgeführt wird (Argument Matching)
public class Account {
...
public void withdraw(double amount) {
balance -= amount;
}
public void withdraw(String code, double amount) {
if (pin.equals(code)) withdraw(amount);
}
}
Account a = new Account();
a.withdraw("12345", 200.0);
Klassen und Objekte
26
Mehrfache Konstruktoren
●
●
Auch Konstruktoren können überladen werden
Mittels this() kann ein Konstruktor einen anderen Konstruktor aufrufen (muss das erste Statement sein)
public class Account {
...
public Account(String name, String code, double amount) {
customer = name; pin = code; balance = amount;
}
public Account(String name, String code) {
this(name, code, 0.0);
}
...
}
Account a = new Account("John", "12345", 1000.0);
Klassen und Objekte
27
this‐Referenz
●
●
Jeder Methode wird implizit die Referenz this auf das eigene Objekt übergeben
this wird oft in Konstruktoren verwendet, um Namenskonflikte zwischen Feldern und Parametern aufzulösen
public class Account {
private String customer;
private String pin;
private double balance = 0.0;
}
Klassen und Objekte
public Account(String customer, String pin) {
this.customer = customer;
this.pin = pin;
}
...
28
Klassenfelder und ‐methoden
●
●
Klassenfelder existieren unabhängig von Objekten einmal pro Klasse und werden zur Speicherung globaler Daten verwendet
Klassenmethoden werden nicht auf einem Objekt sondern auf der Klasse aufgerufen und können nur auf Klassenfelder zugreifen
public class Account {
private static double withdrawLimit;
...
public static int getWithdrawLimit() {
return withdrawLimit;
}
public void withdraw(double amount) {
if (amount <= withdrawLimit)
balance -= amount;
}
}
Account
withdrawLimit
customer
pin
balance
getWithdrawLimit()
deposit()
withdraw()
double limit = Account.getWithdrawLimit();
Klassen und Objekte
29
Konstante Felder
●
Konstante Felder müssen bei ihrer Definition oder im Konstruktor initialisiert werden, danach dürfen sie nicht mehr verändert werden
public class Account {
private static final double WITHDRAW_LIMIT = 5000.0;
...
public void withdraw(double amount) {
if (amount <= WITHDRAW_LIMIT)
balance -= amount;
}
}
Klassen und Objekte
30
Enumerations
Definition von Enums
Enum‐Typen
●
werden verwendet, um Konstanten zu definieren
●
sind Klassen mit einer vordefinierten Menge von Objekten
●
sind implizit von der Standardklasse Enum abgeleitet und erben allgemeine Methoden
public enum Month {
JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
}
for (Month m : Month.values())
System.out.println(m.name() + " has ordinal " + m.ordinal());
Enumerations
32
Verwendung von Enums
Enum‐Werte
●
●
werden mit dem Enum‐Namen und dem Punktoperator referenziert
können mit dem Vergleichsoperator verglichen und in switch‐
Statements verwendet werden
Month month = Month.AUG;
if (month == Month.JAN) ...
int days = 0;
switch (month) {
case JAN: days = 31; break;
case FEB: days = 28; break;
...
case DEC: days = 31;
}
Enumerations
33
Enums mit Feldern und Methoden
●
●
Enums können auch Felder und Methoden haben
Felder von Enums sind final und müssen mit einem privaten Konstruktor initialisiert werden
public enum Month {
JAN(31), FEB(28), MAR(30), ..., DEC(31);
private final int days;
private Month(int days) { this.days = days; }
public int days() { return days; }
}
Month month = Month.AUG;
System.out.println(month + " has " + month.days() + "days");
Enumerations
34
Packages
Definition eines Package
●
●
●
Packages sind hierarchisch aufgebaute Sammlungen von Klassen und definieren Namensräume
Um eine Klasse zu einem Package hinzuzufügen, wird am Anfang des Sourcefiles ein package‐Statement verwendet
Ohne package‐Statement gehören die Klassen zum Default‐Package ohne Namen
package org.bank.account;
public class Account {
...
}
Packages
36
Importieren eines Package
●
●
●
Der vollständige Name einer Klasse setzt sich aus dem Package‐ und dem Klassennamen zusammen
Mit einem import‐Statement können Klassen mit dem Klassennamen allein verwendet werden
Die Klassen aus dem Package java.lang werden defaultmässig importiert
package org.bank;
import org.bank.account.Account;
import org.bank.account.*;
// alle Klassen
public class Bank {
private Account[] accounts;
public static void main(String[] args) { ... }
...
}
Packages
37
Klassenpfad
●
●
●
●
●
Packages
Die Package‐Hierarchien müssen sich in der Verzeichnisstruktur widerspiegeln
Der Klassenpfad enthält die Root‐Verzeichnisse der Package‐
Hierarchien und muss dem Compiler und Interpreter übergeben werden
Directory‐Struktur:
C:\project\src\org\bank\Bank.java
C:\project\src\org\bank\account\Account.java
Kompilation:
C:\project> javac -d bin src\org\bank\account\Account.java
C:\project> javac -cp bin -d bin src\org\bank\Bank.java
Ausführung:
C:\project> java -cp bin org.bank.Bank
38
Vererbung
Ableiten einer Klasse
Eine abgeleitete Klasse
●
erbt alle Felder und Methoden der Basisklasse
●
kann neue Felder und Methoden hinzufügen (Erweiterung)
●
definiert einen zum Typ der Basisklasse kompatiblen Datentyp
public class SavingsAccount extends Account {
private double withdrawLimit;
}
public double getWithdrawLimit() {
return withdrawLimit;
}
Account
customer
pin
balance
deposit()
withdraw()
SavingsAccount
withdrawLimit
getWithdrawLimit()
Vererbung
40
Konstruktorverkettung
●
●
●
Konstruktoren werden nicht vererbt
Mittels super() kann ein Konstruktor der abgeleiteten Klasse einen Konstruktor der Basisklasse aufrufen (muss das erste Statement sein)
Andernfalls wird implizit der Defaultkonstruktor der Basisklasse aufgerufen
public class SavingsAccount extends Account {
private double withdrawLimit;
}
public SavingsAccount(String customer, String pin, double limit) {
super(customer, pin);
withdrawLimit = limit;
}
...
Vererbung
41
Zugriffsrecht protected
●
Protected Felder und Methoden sind in der eigenen Klasse, in Klassen desselben Package und in abgeleiteten Klassen zugreifbar
public class Account {
protected String customer;
protected String pin;
protected double balance;
...
}
public class SavingsAccount extends Account {
...
private boolean isWithdrawalValid(double amount) {
return amount <= withdrawLimit && amount <= balance;
}
}
Vererbung
42
Überschreiben von Methoden
●
●
Eine Methode der abgeleiteten Klasse überschreibt eine Methode der Basisklasse, wenn sie denselben Namen und dieselben Parameter hat
Der Typ des Rückgabewerts beider Methoden muss übereinstimmen
public class SavingsAccount extends Account {
private double withdrawLimit;
...
public void withdraw(double amount) {
if (isWithdrawalValid(amount))
balance -= amount;
}
}
Account
customer
pin
balance
deposit()
withdraw()
SavingsAccount
withdrawLimit
withdraw()
isWithdrawalValid()
Vererbung
43
Aufruf überschriebener Methoden
●
Eine überschriebene Methode kann in der abgeleiteten Klasse weiterhin über die Referenz super aufgerufen werden
public class SavingsAccount extends Account {
private double withdrawLimit;
...
public void withdraw(double amount) {
if (isWithdrawalValid(amount))
super.withdraw(amount);
}
}
Vererbung
44
Dynamische Bindung von Methoden
●
●
Eine Referenz vom Typ einer Basisklasse kann auch auf ein Objekt einer abgeleiteten Klasse zeigen (Polymorphismus)
Beim Aufruf einer überschriebenen Methode entscheidet der aktuelle Objekttyp, welche Methode ausgeführt wird
Account a;
a = new Account(...);
a.withdraw(200.0);
// Methode der Klasse Account
a = new SavingsAccount(...);
a.withdraw(200.0);
// Methode der Klasse SavingsAccount
Vererbung
45
Finale Methoden und Klassen
●
●
Eine finale Methode kann in abgeleiteten Klassen nicht überschrieben werden
Eine finale Klasse kann nicht abgeleitet werden
public class Account {
...
public final String getCustomer() { return customer; }
public final double getBalance() { return balance; }
}
public final class SavingsAccount {
...
}
Vererbung
46
Abstrakte Methoden und Klassen
●
Abstrakte Methoden sind Methoden ohne Implementierung
●
Hat eine Klasse eine abstrakte Methode, so ist die Klasse abstrakt
●
Abstrakte Klassen können nicht instanziiert werden, dienen aber als Basisklassen anderer Klassen
public abstract class Account {
public void deposit(double amount) { ... }
Account
public abstract void withdraw(double amount);
deposit()
}
withdraw()
class SavingsAccount extends Account {
public void withdraw(double amount) { ... }
}
Savings
Personal
class PersonalAccount extends Account {
Account
Account
public void withdraw(double amount) { ... }
}
withdraw()
withdraw()
Vererbung
47
Interfaces
Definition eines Interface
●
●
Ein Interface definiert einen abstrakten Datentyp und beschreibt das Verhalten von Klassen
Alle Methoden eines Interface sind implizit public und abstract
public interface Comparator {
int compare(Object o1, Object o2);
}
Interfaces
50
Implementieren eines Interface
●
●
●
Eine Klasse implementiert ein Interface, indem sie die Methoden des Interface implementiert
Eine Klasse kann mehrere Interfaces implementieren
Eine Klasse ist typkompatibel zu den von ihr implementierten Interfaces
public class AccountComparator implements Comparator {
public int compare(Object o1, Object o2) {
Account a1 = (Account) o1; Account a2 = (Account) o2;
return (int) (a1.getBalance() - a2.getBalance());
}
Comparator
}
compare()
AccountComparator
compare()
Interfaces
51
Anwendung von Interfaces
●
●
Interfaces werden oft als Parameter generischer Methoden verwendet
Als Argumente können Objekte aller Klassen übergeben werden, die das Interface implementieren
public class Util {
public static void sort(Object x[], Comparator c) {
for (int i = x.length - 1; i > 0; i--)
for (int j = 0; j < i; j++)
if (c.compare(x[j], x[j + 1]) > 0) {
Object t = x[j]; x[j] = x[j + 1]; x[j + 1] = t;
}
}
}
Util
sort()
Comparator
compare()
Account[] accounts = ...
Util.sort(accounts, new AccountComparator());
Interfaces
52
Vererbung von Interfaces
●
Ein Interface kann von anderen Interfaces abgeleitet werden, wodurch es alle Methoden des Basis‐Interface erbt
public interface Figure {
void move(int dx, int dy);
void rotate(int angle);
void setColor(Color c);
}
interface ClosedFigure extends Figure {
void setFillColor(Color c);
}
Interfaces
Figure
move()
rotate()
setColor()
ClosedFigure
setFillColor()
53
Innere Klassen
Statische innere Klassen
●
Statische innere Klassen sind Klassen, die innerhalb einer andern Klasse definiert werden und somit zu deren Namensraum gehören
public class Account {
private double balance;
...
public static class BalanceComparator implements Comparator {
public int compare(Object o1, Object o2) {
Account a1 = (Account) o1; Account a2 = (Account) o2;
return (int) (a1.balance - a2.balance);
}
}
}
Account[] accounts = ...
Util.sort(accounts, new Account.BalanceComparator());
Innere Klassen
56
Nicht‐statische innere Klassen
Nicht‐statische innere Klassen
●
●
werden mit einem umgebenden Objekt instanziiert
können auf die Felder und Methoden der umgebenden Klasse zugreifen
public class Account {
private Transaction tx = new Transaction();
private double balance;
...
public void deposit(int amount) {
tx.execute(Transaction.DEPOSIT, amount);
}
private class Transaction {
static final int DEPOSIT = 1, WITHDRAWAL = -1;
void execute(int type, double amount) { balance += type*amount; }
}
}
Innere Klassen
57
Anonyme Klassen
Anonyme Klassen
●
●
haben keinen Namen und werden gerade dort definiert, wo sie gebraucht werden
können auf lokale Variablen zugreifen, die final sind
Account[] accounts = ...
final boolean ascending = ...
Util.sort(accounts, new Comparator() {
public int compare(Object o1, Object o2) {
Account a1 = (Account) o1; Account a2 = (Account) o2;
return ascending ? (int) (a1.getBalance() - a2.getBalance())
: (int) (a2.getBalance() - a1.getBalance());
}
});
Innere Klassen
58
Standardbibliothek
Packages
●
●
Die Standard‐Bibliothek umfasst über 4000 Klassen
Kernklassen sind im Package java, speziellere im Package javax enthalten
Package
java.lang
java.util
java.io, java.nio
java.math
java.net
java.security
java.sql
java.text
java.time
java.awt
Standardbibliothek
Inhalt
Basisklassen (z.B. Object, String, Thread)
Hilfsklassen wie Collections
Ein‐ und Ausgabe
Arithmetik langer Zahlen
Netzwerkkommunikation
Kryptographie
Anbindung relationaler Datenbanken
Internationalisierung
Zeit‐ und Datumswerte
Grafische Benutzeroberflächen
60
Klassenhierarchie
●
In Java gibt es keine Mehrfachvererbung und alle Klassen sind implizit von der Klasse Object abgeleitet
Object
String
Thread
ArrayList
InputStream
FileInputStream
OutputStream
ByteArrayInputStream
Math
Socket
Standardbibliothek
61
Klasse Object
●
Die Methoden der Klasse Object definieren ein gemeinsames Verhalten aller Objekte:
Standardbibliothek
–
toString() erzeugt eine Stringdarstellung eines Objekts
–
equals() vergleicht zwei Objekte
–
hashCode() erzeugt einen Hashcode eines Objekts
–
clone() kopiert ein Objekt
–
finalize() wird aufgerufen, bevor ein Objekt zerstört wird
–
notify(), notifyAll() und wait() dienen der Thread‐Synchronisation
–
getClass() gibt die Klasse eines Objekts zurück
62
Darstellung von Objekten als Strings
●
●
Um eine Darstellung von Objekten als Strings zu erzeugen, kann die Methode toString() überschrieben werden
Diese wird implizit von der Methode String.valueOf() und dem Konkatenationsoperator aufgerufen
public class Account {
private String customer;
private String pin;
private double balance;
...
public String toString() {
return "Account of " + customer + " with balance " + balance;
}
}
Account a = new Account(...);
System.out.println(a + " created");
Standardbibliothek
63
Vergleichen von Objekten
●
●
Um den Zustand von Objekten vergleichen zu können, muss die Methode equals() überschrieben werden
Diese Methode wird u.a. beim Suchen von Objekten in Listen verwendet
public class Account {
...
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof Account)) return false;
Account a = (Account) obj;
return a.customer.equals(customer);
}
}
Account a1 = new Account(...);
Account a2 = new Account(...);
if (a1.equals(a2)) ...
Standardbibliothek
64
Hashcode von Objekten
●
●
Um Objekte effizienter vergleichen zu können, kann die Methode hashCode() überschrieben werden (wobei der Hashcode gleicher Objekte gleich sein muss)
Diese Methode wird u.a. zum Auffinden von Objekten in Hashtabellen verwendet
public class Account {
...
public int hashCode() {
return customer.hashCode();
}
}
Account a1 = new Account(...);
Account a2 = new Account(...);
if (a1.hashCode() == a2.hashCode())
if (a1.equals(a2)) ...
Standardbibliothek
65
Exception‐Handling
Einführung
Exceptions
●
●
●
●
repräsentieren Fehler und ermöglichen, den normalen Programm‐
ablauf von Fehlersituationen zu trennen
enthalten Informationen über den aufgetretenen Fehler
werden geworfen und im Call Stack des Programms automatisch nach oben propagiert
können irgendwo abgefangen und behandelt werden
Exception‐Handling
68
Exception‐Typen
●
●
Die Information über den aufgetretenen Fehler besteht primär aus dem Typ der geworfenen Exception
Es gibt in der Java‐Klassenbibliothek eine grosse Anzahl vordefinierter Exception‐Klassen
Exception
IOException
ParseException
RuntimeException
FileNotFoundException
EOFException
NullPointerException
IllegalArgumentException
IndexOutOfBoundsException
Exception‐Handling
69
Definieren einer Exception
●
●
●
Exception‐Klassen werden von der Standardklasse Exception abgeleitet und repräsentieren Fehlerkategorien
Dem Basiskonstruktor kann eine Fehlermeldung übergeben und mit der Methode getMessage wieder abgefragt werden
Detailinformationen über den aufgetretenen Fehler können in zusätzlichen Feldern enthalten sein
public class TransactionException extends Exception {
public TransactionException(String message) {
super(message);
}
Exception
...
getMessage()
}
printStackTrace()
TransactionException
Exception‐Handling
70
Werfen einer Exception
●
●
Mittels throw kann in einer Methode eine Exception geworfen werden, wodurch die Methode unmittelbar verlassen wird
Exceptions müssen in der throws‐Klausel der Methode deklariert werden
public class Account {
private String customer;
private String pin;
private double balance;
...
public void withdraw(double amount) throws TransactionException {
if (amount > balance)
throw new TransactionException("Insufficient funds");
balance -= amount;
}
}
Exception‐Handling
71
Abfangen einer Exception
●
●
Eine Exception kann mit einem try‐catch‐Statement abgefangen und behandelt werden
Tritt im try‐Block eine Exception auf, so wird unmittelbar in den catch‐
Block verzweigt, andernfalls wird der catch‐Block übersprungen
try {
Account account = findAccount(nr);
account.checkPin(pin);
account.withdraw(amount)
...
}
catch (TransactionException e) {
System.err.println("Error: " + e.getMessage());
}
Exception‐Handling
72
Abfangen verschiedener Exceptions
●
●
●
Verschiedene Exceptions können mit mehreren catch‐Blöcken unterschiedlich behandelt werden
Es wird der erste catch‐Block ausgeführt, dessen Parametertyp zur geworfenen Exception passt
Mit einem catch‐Block können auch mehrere Exceptions gleichzeitig abgefangen werden
try {
Account account = findAccount(nr);
account.checkPin(pin);
account.withdraw(amount);
...
}
catch (IllegalArgumentException e) { ... }
catch (CredentialsException | TransactionException e) { ... }
catch (Exception e) { ... }
// fallback
Exception‐Handling
73
Weitergeben einer Exception
●
●
Nicht abgefangene Exceptions werden im Callstack automatisch nach oben propagiert, müssen aber deklariert werden
Wird eine Exception nirgends abgefangen, so wird der Stack Trace der Exception ausgegeben und das Programm terminiert
public class Bank {
...
public void withdraw(int nr, String pin, double amount)
throws CredentialsException, TransactionException {
Account account = findAccount(nr);
account.ckeckPin(pin);
account.withdraw(amount);
}
}
Exception‐Handling
74
Finally‐Block
●
●
Oft müssen nach einer Fehlerbehandlung Aufräumarbeiten gemacht werden (z.B. Ressourcen freigeben)
Das try‐catch‐Statement hat einen optionalen finally‐Block, der in jedem Fall am Ende ausgeführt wird
try {
Account account = findAccount(nr);
account.checkPin(pin);
account.withdraw(amount);
...
}
catch (IllegalArgumentException e) { ... }
catch (CredentialsException | TransactionException e) { ... }
finally {
log("end of withdrawal");
}
Exception‐Handling
75
Unchecked Exceptions
Unchecked Exceptions
●
repräsentieren unerwartete System‐ oder Programmierfehler
●
sind von der Klasse RuntimeException abgeleitet
●
müssen weder deklariert noch abgefangen werden
public class Account {
private String customer;
private String pin;
private double balance;
...
public Account(String customer, Sting pin) {
if (customer == null || pin == null)
throw new IllegalArgumentException();
...
}
}
Exception‐Handling
Exception
RuntimeException
IllegalArgumentException
76
Collections
Übersicht
●
●
●
Collections erlauben mehrere Objekte zu verwalten
Im Gegensatz zu Arrays haben Collections keine feste Grösse und bieten zahlreiche Methoden zur Manipulation ihrer Elemente
Das Collection‐Framework besteht aus mehreren Interfaces und verschiedenen Implementierungen
Collection
List
ArrayList
LinkedList
Set
HashSet
TreeSet
Map
HashMap
TreeMap
Collections
78
Listen
●
Elemente bleiben in der Reihenfolge, mit der sie hinzugefügt werden
●
Mit dem Index kann direkt auf die Elemente zugegriffen werden
●
Listen werden mithilfe eines Arrays oder als verkettete Liste implementiert
List cities = new ArrayList();
cities.add("London");
cities.add("Paris");
cities.add("London");
cities.add("New York");
...
for (int i = 0; i < cities.size(); i++) {
String city = (String) cities.get(i);
System.out.println(city);
}
accounts.remove(0);
Collections
79
Sets
●
●
●
Sets enthalten keine Duplikate, und die Elemente haben keine bestimmte Reihenfolge (ausser bei TreeSets)
Um auf die Elemente zuzugreifen, muss mit einer for‐each‐Schlaufe über das Set iteriert werden
Sets werden mithilfe von Maps implementiert Set cities = new HashSet();
cities.add("London");
cities.add("Paris");
cities.add("London");
cities.add("New York");
...
for (Object city : cities) {
System.out.println(city);
}
cities.remove("London");
Collections
80
Maps
●
●
●
Maps bilden Objekte (Schlüssel) auf andere Objekte (Werte) ab
HashMaps verwenden den Hashcode der Schlüsselobjekte, um die Wertobjekte zu finden, und sind somit sehr effizient
TreeMaps haben zusätzlich eine Ordnung auf ihren Schlüsseln
Map population = new HashMap();
population.put("London", 8_538_689);
population.put("Paris", 2_240_621);
population.put("London", 8_538_694);
population.put("New York", 8_491_079);
...
for (Object city : population.keySet()) {
System.out.println(city + ": " + population.get(city));
}
population.remove("London");
Collections
81
Iteratoren
●
●
Alle Collections implementieren das Interface Iterable und stellen somit einen Iterator zur Verfügung
Iteratoren sind vor allem nützlich, wenn während einer Iteration Elemente aus der Collection entfernt werden müssen
List accounts = new LinkedList();
...
Iterator iter = accounts.iterator();
while (iter.hasNext()) {
Account a = (Account) iter.next();
if (a.getCustomer() == null)
iter.remove();
}
Collections
82
Generics
Typisierte Collections
●
●
●
Collections können mit einem Typparameter versehen werden
Es können dann nur Objekte vom entsprechenden Typ hinzugefügt werden (Typsicherheit)
Beim Lesen der Elemente sind keine Typumwandlungen notwendig
List<Account> accounts = new ArrayList<Account>();
accounts.add(new Account(...));
accounts.add("London");
// Compiler-Fehler
...
for (int i = 0; i < accounts.size(); i++) {
Account a = accounts.get(i);
System.out.println(a);
}
Generics
84
Typisierte Iteratoren und Comparator
●
●
Iteratoren typisierter Collections haben denselben Typparameter wie die Collection
Zum Sortieren von Collections können typisierte Comparator verwendet werden
Iterator<Account> iter = accounts.iterator();
while (iter.hasNext(); ) {
Account a = iter.next();
System.out.println(a);
}
Collections.sort(accounts, new Comparator<Account>() {
public int compare(Account a1, Account a2) {
return (int) (a1.getBalance() - a2.getBalance());
}
});
Generics
85
Generische Klassen
●
Eine Klasse kann typisiert werden, indem sie mit einem formalen Typparameter versehen wird
public class Box<E> {
private E elem;
public void put(E elem) {
if (this.elem != null) throw IllegalStateException();
this.elem = elem;
}
E take() {
Box
E temp = elem; elem = null; return temp;
elem
}
put()
}
E
take()
Box<Account> box = new Box<Account>();
box.put(new Account(...));
Account a = box.take();
Generics
86
Generische Methoden
●
●
Generische Klassen können als Parameter‐ oder Rückgabetyp von Methoden verwendet werden
Der entsprechende Typparameter muss in der Signatur der Methode aufgeführt werden
public class Util {
public static <E> void reverse(List<E> elems) {
for (int i = 0; i < elems.size() / 2; i++) {
int j = elems.size() - i - 1;
E e = elems.get(i); elems.set(i, list.get(j)); elems.set(j, e);
}
}
}
List<Account> accounts = ...
Util.reverse(accounts);
Generics
87
Beschränkte Typparameter
●
Ein beschränkter Typparameter steht für Typen, die eine gemeinsame Basisklasse haben
public class Util {
public static <E extends Number> double sum(List<E> elems) {
double sum = 0;
for (E elem : elems) {
sum += elem.doubleValue();
}
return sum;
}
}
List<Integer> integers = ...
Util.sum(integers);
Generics
88
Generics und Vererbung
●
●
Es gibt keine Typbeziehung zwischen den Instanziierungen einer typisierten Collection, selbst wenn die Typparameter kompatibel sind
Der Grund liegt darin, dass nach einer Zuweisung die Typsicherheit nicht mehr gewährleistet wäre
List<Integer> integers = new ArrayList<>();
integers.add(42);
...
List<Number> numbers = integers;
// Compiler-Fehler
numbers.add(3.14159);
integers.get(1);
Generics
89
Wildcard‐Typen
●
●
●
Ein Wildcard‐Typ ist eine Collection, deren Elemente von unbe‐
kanntem Typ sind
Jede Instanziierung der entsprechenden Collection ist typkompatibel zum Wildcard‐Typ
Wildcard‐Typen dürfen keine Elemente hinzugefügt werden
List<Integer> integers = new ArrayList<>();
integers.add(42);
...
List<?> elems = integers;
Object elem = elems.get(0);
elems.add(3.14159);
// Compiler-Fehler
Generics
90
Ein‐ und Ausgabe
Dateien und Pfade
●
Die Klasse File repräsentiert Dateipfade und stellt u.a. folgende Methoden zur Verfügung:
Ein‐ und Ausgabe
–
exists() gibt an, ob eine Datei mit dem Pfad existiert
–
length() gibt die Grösse der Datei zurück
–
isFile(), isDirectory() geben den Typ der Datei an
–
canRead(), canWrite(), canExecute() geben die Zugriffsrechte an
–
createNewFile() erzeugt eine neue Datei
–
mkdir() erzeugt ein Verzeichnis
–
delete() löscht die Datei
92
Verzeichnisse
●
●
Die Methode listFiles() der Klasse File erlaubt, die Dateien eines Verzeichnis abzufragen
Mit einem FileFilter können die Dateien zudem gefiltert werden
public class ListDir {
public static void main(String[] args) {
File dir = new File(args[0]);
File[] files = dir.listFiles(new FileFilter() {
public boolean accept(File file) { return file.isFile(); }
});
for (File file : files) {
System.out.println(file.getName() + " (" + file.length() + " bytes)");
}
}
}
Ein‐ und Ausgabe
93
Streams
●
Die Ein‐ und Ausgabe erfolgt über sogenannte Streams
●
Streams erlauben das iterative Lesen und Schreiben von Daten
●
Streams können zu einer Pipeline verkettet werden
●
Es gibt Streams zur eigentlichen Ein‐/Ausgabe bzw. Streams zur Verarbeitung von Daten
Verarbeitung
Programm
Ein‐ und Ausgabe
Ein‐/Ausgabe
Daten
quelle
94
Ein‐/Ausgabe‐Streams
Je nach Art der zu lesenden bzw. schreibenden Daten wird zwischen Byte‐ und Character‐Streams unterschieden
Datenquelle Byte‐Streams
Character‐Streams
File
FileInputStream
FileOutputStream
FileReader
FileWriter
Array
ByteArrayInputStream
ByteArrayOutputStream
CharArrayReader
CharArrayWriter
StringReader
StringWriter
String
Pipe
PipedInputStream
PipedOutputStream
PipedReader
PipedWriter
Ein‐ und Ausgabe
95
Verarbeitungs‐Streams
Verarbeitung
Byte‐Streams
Umwandlung von
Bytes in Characters
Character‐Streams
InputStreamReader
OutputStreamWriter
Umwandlung primi‐
tiver Typen in Bytes
DataInputStream
DataOutputStream
Umwandlung von
Objekten in Bytes
ObjectInputStream
ObjectOutputStream
Pufferung von Daten
BufferedInputStream BufferedReader
BufferedOutputStream BufferedWriter
Filterung von Daten
FilterInputStream
FilterOutputStream
FilterReader
FilterWriter
Formatierung
PrintStream
PrintWriter
Zudem können mit der Utility‐Klasse Scanner primitive Typen einfach gelesen werden
Ein‐ und Ausgabe
96
Schliessen von Streams
●
●
Streams sollten geschlossen werden, wenn sie nicht mehr gebraucht werden
Da Streams das Interface AutoCloseable implementieren, kann dazu das try‐with‐resources‐Statement verwendet werden
try (FileReader reader = new FileReader(...)) {
int c = reader.read();
...
} catch (IOException e) {
System.err.println("Fehler: " + e.getMessage());
}
Ein‐ und Ausgabe
97
Lesen und Schreiben von Binärdaten
●
Ein InputStream erlaubt das Lesen, ein OutputStream das Schreiben von Binärdaten
public class Copy {
public static void main(String[] args) throws IOException {
try (FileInputStream in = new FileInputStream(args[0]);
FileOutputStream out = new FileOutputStream(args[1])) {
}
Ein‐ und Ausgabe
}
}
byte[] buffer = new byte[1024];
while (true) {
int nbytes = in.read(buffer);
if (nbytes == -1) break;
out.write(buffer, 0, nbytes);
}
98
Lesen und Schreiben von Textdaten
●
Ein Scanner erlaubt das zeilenweise Lesen, ein PrintWriter das zeilenweise Schreiben von Textdaten
public class Note {
public static void main(String[] args) throws IOException {
try (Scanner in = new Scanner(System.in);
PrintWriter out = new PrintWriter(new FileWriter(args[0]))) {
}
}
}
while (true) {
String line = in.nextLine();
if (line.isEmpty()) { break; }
out.println(line);
}
Ein‐ und Ausgabe
99
Objekt‐Serialisierung
●
●
Objekt‐Serialisierung ist ein Mechanismus zum Lesen und Schreiben ganzer Objektbäume
Damit die Objekte einer Klasse serialisiert werden können, muss die Klasse das leere Interface Serializable implementieren
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
private Date date = new Date();
private String text;
}
Ein‐ und Ausgabe
public Message(String text) { this.text = text; }
public Date getDate() { return date; }
public String getText() { return text; }
100
Schreiben von Objekten
●
Die Klasse ObjectOutputStream erlaubt das Schreiben von Objekten
public class PostIt {
public static void main(String[] args) throws Exception {
try (Scanner scanner = new Scanner(System.in);
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream(args[0]))) {
}
}
}
String text = scanner.nextLine();
Message msg = new Message(text);
out.writeObject(msg);
Ein‐ und Ausgabe
101
Lesen von Objekten
●
Die Klasse ObjectInputStream erlaubt das Lesen von Objekten
public class ReadIt {
public static void main(String[] args) throws Exception {
try (ObjectInputStream in = new ObjectInputStream(
new FileInputStream(args[0]))) {
}
Ein‐ und Ausgabe
}
Message msg = (Message) in.readObject();
Date date = msg.getDate();
String text = msg.getText();
System.out.println(date + "\n" + text);
} catch (FileNotFoundException e) {}
102
Threads
Einführung
●
Threads sind parallele Ablaufeinheiten innerhalb eines Prozesses und werden u.a. eingesetzt bei
–
Ein‐/Ausgabe‐Operationen, die blockieren können
–
der Behandlung externer Ereignisse
–
der Ausführung periodischer Aufgaben
Haupthread
start
join
Nebenthread
run
Threads
104
Klasse Thread
●
●
●
In Java werden Threads durch Objekte der Standard‐Klasse Thread repräsentiert
Ein Thread‐Objekt enthält in der run()‐Methode den Code, der im zugehörigen Thread ausgeführt werden soll
Über das Thread‐Objekt kann der Thread gesteuert werden:
–
start() startet den Thread
–
join() wartet auf die Terminierung des Threads
–
sleep() unterbricht den Thread für eine bestimmte Zeit
–
interrupt() setzt ein Flag, um den Thread vorzeitig zu beenden
–
setPriority() bestimmt die Priorität des Thread
Threads
105
Thread‐Zustände
●
Ein Thread durchläuft verschiedene Zustände
–
Created: das Thread‐Objekt existiert, aber der zugehörige Thread wurde noch nicht gestartet
–
Runnable: der Thread wurde gestartet und ist lauffähig
–
Non‐Runnable: der Thread ist nicht lauffähig, weil er z.B. in einer Ein‐/Ausgabe‐Operation blockiert ist
–
Dead: der Thread hat terminiert
Created
Runnable
Dead
Non‐Runnable
Threads
106
Erzeugen eines Threads (Variante 1)
●
●
Um einen Thread zu erzeugen, wird von der Standardklasse Thread eine Klasse abgeleitet, die run()‐Methode überschrieben, die Klasse instanziiert und die start()‐Methode aufgerufen
Das Runtime‐System erzeugt dann den eigentlichen Thread, welcher die run()‐Methode des Thread‐Objekts ausführt
public class CounterThread extends Thread {
private int max;
public CounterThread (int max) { this.max = max; }
public void run() {
for (int i = 1; i <= max; i++) System.out.println(i);
}
}
CounterThread thread = new CounterThread(100);
thread.start();
...
thread.join();
Threads
107
Erzeugen eines Threads (Variante 2)
●
Um ein Thread‐Objekt zu erzeugen, kann auch die Klasse Thread instanziiert und dem Konstruktor ein Objekt übergeben werden, welches das Interface Runnable implementiert
public class CounterRunnable implements Runnable {
private int max;
public CounterRunnable(int max) { this.max = max; }
public void run() {
for (int i = 1; i <= max; i++) System.out.println(i);
}
}
CounterRunnable runnable = new CounterRunnable(100);
Thread thread = new Thread(runnable);
thread.start();
...
thread.join();
Threads
108
Terminieren eines Threads
●
●
Ein Thread terminiert, wenn er die run()‐Methode verlässt
Um einen Thread vorzeitig zu beenden, kann mittels interrupt() ein Flag gesetzt werden, welches der Thread mittels interrupted() periodisch prüft
public class CounterThread extends Thread {
public void run() {
int i = 1;
while (!Thread.interrupted()) { System.out.println(i++); }
}
}
CounterThread thread = new CounterThread();
thread.start();
...
thread.interrupt();
Threads
109
Synchronisieren von Methoden
●
●
Um Zugriffskonflikte auf die Felder eines Objekts zu vermeiden, können die Methoden als synchronized markiert werden
Für dasselbe Objekt kann dann immer nur ein Thread gleichzeitig eine der entsprechenden Methoden ausführen (exklusiver Ausschluss)
public class Buffer {
private Object[] elems = new Object[...];
private int size = 0;
}
Threads
public synchronized void put(Object obj) {
for (int i = size++; i > 0; i--) { elems[i] = elems[i - 1]; }
elems[0] = obj;
}
public synchronized Object get() {
return elems[--size];
}
110
Warten auf eine Bedingung
●
●
Mittels wait() kann ein Thread innerhalb einer synchronisierten Methode auf eine Bedingung warten, bis diese von einem andern Thread mittels notify() im gleichen Objekt signalisiert wird
Warten mehrere Threads, so können alle Threads mittels notifyAll() geweckt werden
public class SynchronizedBuffer {
...
public synchronized void put(Object obj) {
...
notify();
}
public synchronized Object get() throws InterruptedException {
while (size == 0) wait();
return elems[--size];
}
}
Threads
111
Zugehörige Unterlagen
Herunterladen