datei-handling anonyme klassen - uni-muenster.de · •damit ist system.out.println(…) unter...
TRANSCRIPT
Name: Patrick Förster
Enums
• Enums sind eine Aufzählung von int-Werten, wobei jedes Element einem
bestimmten Namen zugeordnet ist • In Java werden Enums über das Schlüsselwort enum definiert und sind
spezielle Klassen:
• Lediglich die Namen werden angegeben und werden per Konvention komplett in Großbuchstaben notiert (analog zu konstanten Klassenattributen) • Die Werte werden konsekutiv angefangen bei 0 einem int-Wert zugeordnet • Ein Zugriff erfolgt über die Dereferenzierung des Klassennamens:
2 Programmieren in Java
Slot.PROCESSOR
SICHTBARKEIT KLASSEN-BEZEICHNER { enum
}
ENUM-BEZEICHNER ,
…
public enum Slot {
PROCESSOR,
RAM,
…
}
Name: Patrick Förster
Inner-Class
• In Java können Klassen/Interfaces innerhalb von Klassen/Interfaces definiert werden
• Der Zugriff auf innere Klassen erfolgt analog zu Klassenattributen über den umschließenden Klassennamen
• Nur bei inneren Klassen kann der Modifikator static genutzt werden
3 Programmieren in Java
MODIFIKATOREN KLASSEN-BEZEICHNER { class|enum
}
…
MODIFIKATOREN
}
…
KLASSEN-BEZEICHNER { class|enum
public interface Pluggable {
public static enum Slot {
PROCESSOR,
RAM,
}
…
}
Pluggable.Slot slot = Pluggable.Slot.PROCESSOR;
Name: Patrick Förster
Inner-Class
• Innerhalb eines Interfaces sind alle inneren Klassen automatisch static
• Geeignete Sichtbarkeit vorausgesetzt können von außen nur Instanzen von statischen inneren Klassen erzeugt werden:
• Instanzen nicht statischer innerer Klassen können nur innerhalb von Instanzen der umschließenden Klasse erzeugt werden:
• Jede Instanz einer nicht statischen inneren Klasse hat Zugriff auf die Instanz, die sie erzeugt hat und damit auf deren Attribute und Methoden
4 Programmieren in Java
GraphicsCard.Resolution resolution = new GraphicsCard.Resolution(…);
GraphicsCard.Resolution resolution = new GraphicsCard.Resolution(…); // Resolution nicht statisch
// Resolution statisch
public class GraphicsCard {
public class Resolution {…}
…
public Resolution createResolution(int width, int height) {
return new Resolution(width, height);
}
}
Name: Patrick Förster
• Java bietet mit Exceptions eine Alternative zur Fehlerbehandlung • Exception ist eine Java-Klasse • Die Ausführung einer Methode kann jederzeit durch das „Werfen“ einer Exception-Instanz beendet werden • Methoden, die durch eine Exception abgebrochen werden könnten, müssen diese in ihrer Signatur nach dem Schlüsselwort throws angeben
• Innerhalb der Methode wird eine Exception-Instanz mittels throw geworfen:
• Die Ausführung der Methode wird mit throw abgebrochen, d.h. nachfolgender
Code wird nicht mehr ausgeführt • Der Methodenaufruf wird keine Rückgabe liefern
Fehlerbehandlung durch Exceptions
5 Programmieren in Java
public void plugin(Pluggable pluggable) throws Exception{…}
MODIFIKATOREN RÜCKGABETYP ( BEZEICHNER … throws } EXCEPTION-TYP , … ;
if (!slotAvailableFor(pluggable.getSlot())) {
throw new Exception("FEHLERMELDUNG");
}
Name: Patrick Förster
• Man betrachte folgende Methodensignatur und Methodenaufruf
• Der Aufruf createSomething() könnte nach Signatur zu einer Exception
führen • Kommt es zum Fehlerfall, liefert der Aufruf kein Ergebnis • Die Variable something bleibt also „uninitialisiert“
• Variablen müssen in Java vor ihrer ersten Auswertung initialisiert sein, ansonsten kommt es zum Compilefehler • Damit ist System.out.println(…) unter Umständen nicht compilierbar
• Um diesen Konflikt zu vermeiden, bietet Java die Möglichkeit Codeblöcke „versuchsweise“ auszuführen • Das dafür vorgesehene Sprachkonstrukt nennt sich try-catch-Block
Fehlerbehandlung durch Exceptions
6 Programmieren in Java
public Object createSomething() throws Exception{…}
Object something = createSomething();
System.out.print(something);
Name: Patrick Förster
optional
Try-Catch-Finally
7 Programmieren in Java
{ try
}
…
AUFRUF EINER METHODE, DIE MIT THROWS DEFINIERT WURDE
…
catch ( ) EXCEPTION-TYP BEZEICHNER_1 {
}
FEHLERBEHANDLUNG
catch ( ) EXCEPTION-TYP BEZEICHNER_N { } …
CircuitBoard board = …;
Pluggable pluggable = …;
try {
…
board.plugin(pluggable);
… // wird nicht mehr ausgeführt
… // falls der plugin-Aufruf
… // zu eine Exception geführt
… // hat
…
}
catch (Exception e) {
System.out.println(
e.getMessage()
);
}
…
…
finally {
System.out.println(
"Dies wird immer ausgeführt"
);
}
finally {
}
…
Name: Patrick Förster
• Da Exception eine Java-Klasse ist, kann von ihr geerbt werden • Durch Vererbung von Exception können eigene Exceptions definiert werden
Eigene Exceptions
8 Programmieren in Java
public class ConfigurationException extends Exception {
public ConfigurationException(String message) {
super(message);
}
…
}
…
public void plugin(Pluggable pluggable) throws ConfigurationException {…}
…
CircuitBoard board = …;
Pluggable pluggable = …;
try {
board.plugin(pluggable);
…
}
catch (ConfigurationException e) {
System.out.println(e.getMessage() );
}
if (!slotAvailableFor(pluggable.getSlot())) {
throw new ConfigurationException (
"FEHLERMELDUNG"
);
}
Name: Patrick Förster
• Nicht alle Exceptions müssen per throws signalisiert werden • Ebenso müssen nicht alle Exceptions mit try-catch abgefangen werden:
• Bspw. kann es schnell zur NullPointerException kommen • Oder ArrayOutOfBounds-Exception beim Zugriff auf ein Array-Element • Solche Exceptions mussten aber an keiner Stelle explizit mit try-catch
abgefangen werden
• Exceptions, die weder per throws signalisiert noch per try-catch
abgefangen werden müssen, werden als Laufzeit-Exceptions bezeichnet • All Laufzeit-Exceptions erben von der Klasse RuntimeException • Wird eine RuntimeException nicht abgefangen, so kommt es unmittelbar
zum Programmabbruch!
Laufzeit-Exceptions
9 Programmieren in Java
Name: Patrick Förster
• Module repräsentiert alle Slots eines bestimmten Typs auf einer Platin
• Da jeder Slot nur mit der zugehörigen Platine existiert: Aggregation • Aggregation lässt sich im Code sehr gut durch innere Klassen abbilden:
• Die Klasse ist protected um den Zugriff„von außen“ einzuschränken • Mit max wird definiert, wie viele Slots des Typs maximal vorhanden sind • Die Methoden plugin sowie add werfen eine Exception falls das übergebene Pluggable-Objekt nicht hinzugefügt werden kann
Anwendung
10 Programmieren in Java
Module
Pluggable[] slots;
Pluggable.Slot slot;
int max;
add(Pluggable): void
throws ConfigurationException
CircuitBoard
Module[] modules;
plugin(Pluggable): void
throws ConfigurationException
createModule(Pluggable.Slot, int size): Module
<<interface>>
Pluggable
1 n 1 n
public class CircuitBoard {
protected class Module {…}
}
Name: Patrick Förster
• Die unterstützen Slot-Typen sind je nach Platine unterschiedlich • Über die Methode createModule können die unterstützten Slot-Typen als
Modul hinzugefügt werden • Im Entwurf wurde festgelegt, dass auf jeder Platine ein Prozessor sitzt
• createModule ist protected, um den Aufruf „von außen“ zu vermeiden • Die Methode plugin wird eine ConfigurationException, falls ein Pluggable-Objekt hinzugefügt werden soll, für das kein Slot-Modul existiert
Anwendung
11 Programmieren in Java
…
public CircuitBoard(String name, Processor processor) {
…
try {
Module module = try.createModule(Pluggable.Slot.PROCESSOR, 1);
module.add(processor);
}
catch (ConfigurationException e) {
throw new RuntimeException(e);
}
}
…
Name: Patrick Förster
Anwendung
12 Programmieren in Java
Computer
GraphicsCard
RAMModule
Device
Soundcard Harddrive
Connector
CircuitBoard
<<interface>>
Pluggable
Processor
1
Module
Name: Patrick Förster
• Stream: Fluss von Bytes zwischen einem Sender und einem Empfänger • Ein Stream, der von einer Datenquelle kommt, ist ein InputStream • Ein Stream, der an eine Datenquelle geschickt wird, ist ein OutputStream.
• In Java erfolgt das Einlesen von Dateiinhalten über Datei-Streams • Der Zugriff auf eine Datei erfolgt über ihren Dateipfad • Ein Pfadobjekt wird über die Hilfsklasse java.nio.file.Paths erzeugt:
• Dabei spielt keine Rolle, ob überhaupt eine Datei namens „test.txt“ existiert • Erst beim Zugriff (Lesen/Schreiben) wird überprüft, ob die Datei existiert • Java überprüft selbständig welches Trennzeichen für Ordner auf dem aktuellen Betriebssystem zugelassen ist • Ob also \ (Windows) oder / (Linux) ist in der Angabe egal
• Ohne führendes Trennzeichen wird dem angegebenen Pfad der Pfad der Anwendung vorangestellt • In Netbeans ist dies der Ordner, der den src-Ordner enthält
Einlesen von Dateien
13 Programmieren in Java
Path path = Paths.get("files/test.txt");
Name: Patrick Förster
• Über die Hilfsklasse java.nio.file.Files wird ein InputStream erzeugt
• Natürlich muss dafür die angegebene Datei existieren • Ob eine Datei existiert, wird ebenfalls über Files angefragt
• Nun könnte mit stream.read() Byte für Byte der Dateiinhalt gelesen werden
• Lese- und Schreibeoperationen werden standardmäßig ohne Puffer ausgeführt • D.h. jede Lese- bzw. Schreibeoperation wird an das Betriebssystem delegiert • Das kann ein Programm allerdings sehr ineffektiv machen • Daher werden InputStreams meist um einen Puffer erweitert
• Der Stream ließt dann solange von diesem Puffer bis dieser leer ist • Erst dann erfolgt ein Betriebssystemaufruf
Einlesen von Dateien
14 Programmieren in Java
Path path = Paths.get("files/test.txt");
InputStream stream = Files.newInputStream(path);
if (Files.exists(path)) {
…
}
else {…}
Name: Patrick Förster
• Ein InputStream wird durch eine sogenannte „Wrapper“-Klasse durch
einen Puffer erweitert
• Da BufferedInputStream selbst wieder ein InputStream ist, kann überall da wo ein InputStream benötigt wird, ein gepufferter eingesetzt werden
• Es sei nun davon ausgegangen, dass der Inhalt einer Datei ein Text ist • Liest man Byte für Byte müsste man diese Bytes zu Text „umwandeln“ • Diesen Aufwand kann man sich allerdings sparen, da die Java-API bereits Klassen anbietet, welche diese Aufgabe übernehmen:
• Kürzer:
Einlesen von Dateien
15 Programmieren in Java
InputStream stream = Files.newInputStream(path);
InputStreamReader reader = new InputStreamReader(stream);
BufferedReader buffer = new BufferedReader(reader);
BufferedReader buffer = Files.newBufferedReader(path);
Path path = Paths.get("files/test.txt");
InputStream stream = Files.newInputStream(path);
BufferedInputStream buffer = new BufferedInputStream(path);
Name: Patrick Förster
• Mit der Methode readLine des BufferedReader kann eine Datei nun Zeile
für Zeile eingelesen werden
• Nach dem Einlesen einer Datei muss der InputStream geschlossen werden
Einlesen von Dateien
16 Programmieren in Java
String line;
StringBuilder out = new StringBuilder();
while ((line = reader.readln()) != null) out.append(line).append("\n");
stream.close();
try {
// STREAM ERZEUGEN
try {
// STREAM EINLESEN
}
finally {
try {
// STREAM SCHLIEßEN
}
catch (IOException io) {…}
}
}
catch (IOException io) {…}
• Die meisten Datei-Operationen können zu einer IOException
führen • Erzeugung, Einlesen und Schließen des Streams sollten getrennt werden, um in jedem Fall die Change zu haben den Stream zu schließen
Name: Patrick Förster
• Mit Java 7 wurde die try-catch-Anweisung um das automatische
Schließen von Ressourcen erweitert • Als Ressource werden alle Objekte angesehen, die das Interface java.io.Closeable implementieren
• Ein InputStream ist Closable:
Path path = Paths.get("files/test.txt");
StringBuilder out = new StringBuilder();
try (InputStream stream = Files.newInputStream(path)) {
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
String line;
while ((line = reader.readln()) != null) out.append(line).append("\n");
}
catch (IOException io) {…}
Einlesen von Dateien
17 Programmieren in Java
( try
}
…
Closeable { = BEZEICHNER … )
…
Name: Patrick Förster
• Das Schreiben in eine Datei verläuft im Prinzip analog • Anstelle eines InputStreams wird nun ein OutputStream verwendet • Wie beim InputStream sollte ein Puffer eingesetzt werden
• Das Beispiel baut darauf das Text in eine Datei geschrieben werden soll
• Die Schreiboperation wird auf dem Puffer ausgeführt • Die wirkliche Datei ist damit noch nicht mit dem Inhalt gefüllt • Mit flush wird der Pufferinhalt in die Datei übertragen (Betriebssystem) • Obiges kann man über die Hilfsklasse Files in einem Aufruf erledigen:
Schreiben in Dateien
18 Programmieren in Java
String content = …;
Path path = …;
try (OutputStream stream = Files.newOutputStream(path)) {
BufferedWriter writer = new BufferedWriter (new OutputStreamReader(stream));
writer.write(content);
writer.flush();
}
catch (IOException io) {…}
try {
Files.write(path, content.getBytes());
catch (IOException io) {…}
Name: Patrick Förster
• Über einen DirectoryStream werden alle Dateien eines Ordners eingelesen • DirectoryStream ist ebenfalls Closeable (erbt nicht von InputStream) • Über Files kann festgestellt werden, ob ein Pfad einem Ordner entspricht
• Man beachte: Die for-Iteration läuft über Objekt-Instanzen • Man würde Path erwarten
• Dies ist in Wirklichkeit auch der Fall, nur ist es mit den bisherigen Mitteln nicht möglich den Compiler davon zu überzeugen
• Siehe: Vorlesung „Generische Datentypen“
Ordnerinhalte einlesen
19 Programmieren in Java
Path path = …
if (Files.isDirectory(path)) {
try (DirectoryStream stream = Files.newDirectoryStream(path)) {
for (Object object : stream) {
System.out.println(object);
}
}
catch (IOException io) {…}
}
Name: Patrick Förster
• Dem newDirectoryStream-Aufruf kann ein weiterer Parameter mitgegeben
werden, über den die Ordnerinhalte gefilter werden können • Der Parameter ist vom Typ java.nio.file.DirectoryStream.Filter • Filter ist ein Interface mit einer Methode:
• Ein möglicher Filter, der nur Dateien mit der Endung .txt liefert:
• Einbinden:
Ordnerinhalte filtern
20 Programmieren in Java
public static class MyFilter implements DirectoryStream.Filter {
public boolean accept(Object entry) {
Path path = (Path) entry;
path = path.getName(path.getNameCount() - 1);
return path.toString().endsWith(".txt");
}
}
boolean accept(Object entry) throws IOException;
MyFilter filter = new MyFilter();
try (DirectoryStream stream = Files.newDirectoryStream(path, filter)) {…}
catch (IOException io) {…}
Name: Patrick Förster
• Java bietet die Möglichkeit anonyme Klassen zu definieren • D.h. Klassen, für die kein Name vergeben wird • Da diese Klassen allerdings keinen Namen haben, kann man sie nicht wie gewohnt über class definieren
• Die Definition findet quasi „ad hoc“ mit der Initialisierung einer Instanz statt • Und ist immer die Erweiterung einer bestehenden Klasse oder die Implementierung eines Interfaces
• Es kann keine Instanz von DirectoryStream.Filter erzeugt werden
• Hier wird eine anonyme Klasse definiert, die das Interface implementiert • Und direkt eine Instanz dieser Klasse erzeugt • Die dann einem Instanzattribut zugewiesen wird • Anonyme Klassen sind nicht statische innere Klassen
Anonyme Klassen
21 Programmieren in Java
private DirectoryStream.Filter filter = new DirectoryStream.Filter() {
public boolean accept(Object entry) {
// wie oben
}
};
Name: Patrick Förster
• Da anonyme Klasse nicht statisch sind, kann innerhalb der Implementierung auf alle Attribute der umschließenden Klasse zugegriffen werden • Anonyme Klassen können auch innerhalb einer Methode definiert werden:
• Insbesondere können so Parameter an die Klasse übergeben werden • Allerdings müssen die Parameter dafür als final deklariert werden
Anonyme Klassen
22 Programmieren in Java
public void filter() {
private DirectoryStream.Filter filter = new DirectoryStream.Filter() {
public boolean accept(Object entry) {/* wie oben */}
};
try (DirectoryStream stream = Files.newDirectoryStream(path, filter)) {…}
catch (IOException io) {…}
}
public void filter(final String extension) {
private DirectoryStream.Filter filter = new DirectoryStream.Filter() {
public boolean accept(Object entry) {
Path path = (Path) entry;
return path.getName(path.getNameCount() - 1).toString().endsWith(extension);
}
};
}
Name: Patrick Förster
• Lassen Sie die Klasse Harddrive das Interface FileHandler implementieren
Aufgabe
23 Programmieren in Java
public interface FileHandler {
/*
Liest den Inhalt der Datei mit dem Pfad „fileName“ ein und liefert diesen zurück
Schmeißt eine IOException, falls die Datei nicht existiert oder das Einlesen fehlschlägt
*/
String read(String fileName) throws IOException;
/*
Speicher den als „content“ angegebenen Text in der Datei mit dem Pfad „fileName“ ab
Schmeißt eine IOException, falls das Schreiben fehlschlägt
*/
void save(String fileName, String content) throws IOException;
/*
Löscht die Datei mit dem Pfad „fileName“
Die Methode soll „false“ liefern, falls die angegebene Datei nicht existiert, ansonsten true
Schmeißt eine IOException falls das Löschen fehlschlägt
*/
boolean delete(String fileName) throws IOException;
/*
Liefert einen Path-Array mit allen Pfaden zu Dateien, die die Endung „extension“ haben
Schmeißt eine IOException falls der Ordnerpfad nicht existiert oder das Einlesen fehlschlägt
*/
Path[] delete(String directoryName, final String extension) throws IOException;
};