Auszug einiger Java Pakete

Werbung
Java Schulung
Objektorientierte Programmierung in Java
Teil VI: Wichtige Java Pakete
Prof. Dr. Nikolaus Wulff
Java Pakete
• Für die meisten Aufgaben stellt Java bereits viele nützliche
Bibliotheken zur Verfügung:
– Datei Ein- und Ausgabe java.io
– Container Klassen java.util
– Logging API java.util.logging
– Netzwerk und Socket Programmierung java.net
– Datenbankzugriffe java.sql
– Graphische Benutzerschnittstellen java.awt und
javax.swing
• Das Problem ist lediglich das richtige Paket für die
gestellte Aufgabe zu finden :-(
Prof. Dr. Nikolaus Wulff
2
java.io
• Das java.io Paket enthält die wichtigen
Konzepte zur Manipulation von Dateien und das
Arbeiten mit Streams:
– File
– Input- und OutputStream
– Reader und Writer
• Die Streams und Reader/Writer Klassen sind nach
dem Unix Pipe Konzept modelliert und lassen sich
nahezu beliebig verschachteln.
Prof. Dr. Nikolaus Wulff
3
Input Klassenhierarchie
System
InputStream
(from lang)
-in
+$in
FilterInputStream
ByteArrayInputStream
ObjectInputStream
StringBufferInputStream
L ineNumberInp utStre am
-dis
DataInputStream
PipedInputStream
BufferedInputStream
PushbackInp utStre am
io
(from java)
-fd
Fil eInputStream
FileDescriptor
+$out
+$err
+$in
IOExcep tion
Strin g
-path
(from lang)
File
+$separator
+$pathSeparato r
Prof. Dr. Nikolaus Wulff
4
Output Klassenhierarchie
<<Interface>>
ObjectStreamConstants
OutputStream
#out -out
<<Interface>>
ObjectOutput
PipedOutp utStre am
FilterOutputStream
Ob jectOutputStream
ByteArrayOutputStream
-dos
io
BufferedOutputStream
DataOutputStream
(from java)
Prin tStrea m
OutputStreamWriter
-charOut
IOException
+$out
FileOutputStream
FileDescriptor
-fd
System
+$out
Prof. Dr. Nikolaus Wulff
(from lang)
5
Reader
• Die Reader Klassen kapseln
Texteingaben.
• Häufig verwenden sie im
Konstruktor einen
InputStream, von dem sie
die Daten einlesen.
InputStream
Reader
#in
-in
InputStreamReader
StringReader
BufferedReader
Fil terReader
PipedReader
CharArrayReader
FileReader
Prof. Dr. Nikolaus Wulff
– Beispiel InputStream- und
FileReader
• Die Reader lassen sich
verschachteln.
6
Writer
Writer
PipedWriter
-out
-out
CharArrayWriter
PrintWriter
Fil terWri ter
StringWrite r
OutputStreamWriter
BufferedWriter
• Die Writer Hierarchie besteht aus Klassen für
Textausgaben.
• Sie ist ähnlich strukturiert wie die Reader Hierarchie.
Prof. Dr. Nikolaus Wulff
7
Fehler über Fehler...
EOFException
io
IOException
(from java)
FileNotFoundException
InterruptedIOException
SyncFailedException
Ob jectStreamException
CharConversionException
UTFDataFormatException
NotActiveException
UnsupportedEncodingException
Invali dC lass Excepti on
StreamCorruptedException
Invali dObjectException
OptionalDataException
WriteAbortedException
Prof. Dr. Nikolaus Wulff
8
Übung
• Entwickeln Sie das Unix Head Utility
–
–
–
–
–
Head schreibt die ersten 10 Zeilen einer Datei auf die Console.
Die Anzahl der zu lesenden Zeilen kann vorgegeben werden.
Testen Sie mit JUnit!
Die Ausgabe kann in eine Datei umgeleitet werden.
Aufruf: java Head dateiname [-o ausgabedatei] [-l anzahl zeilen]
• Ziele:
– Kennenlernen der io-Klassen:
• File & FileInput/OutputStream, LineNumberReader
• Stream Verkettungen
– Datei IO sinnvoll mit JUnit testen, temporäre Dateien anlegen.
Prof. Dr. Nikolaus Wulff
9
Head in Aktion
Aufruf
Verwendete Klassen
Ausgabe Schleife
Zeilen
zählen!
Prof. Dr. Nikolaus Wulff
10
Ströme verketten
• Die Java IO-Ströme lassen sich wie bei der Unix
Pipe Architektur verketten.
• Dadurch ist es möglich Filter dazwischen zu
schalten oder Ströme mit neuen Eigenschaften zu
dekorieren.
Eingabe
Datei
FileInputStream
copy(from, to)
Ausgabe
Datei
FileOutputStream
GZIPOutputStream
Prof. Dr. Nikolaus Wulff
11
Ein ZIP Strom
• Die Verkettung von Strömen ist recht einfach:
OutputStream out;
out = new FileOutputStream(destination);
out = new BufferedOutputStream(out);
out = new GZIPOutputStream(out);
• und hier die generische Kopiermethode:
protected void copy(InputStream in,
OutputStream out) throws IOException
{
byte[] buf = new byte[4096];
int read, EOF = -1;
while( (read = in.read(buf)) != EOF) {
out.write(buf, 0, read);
}
}
Prof. Dr. Nikolaus Wulff
12
Filter als Ströme
• Durch die Verkettung von Eingabe- oder Ausgabeströmen lassen sich sehr einfach und modular Filter
entwickeln.
• Es muss lediglich ein zusätzlicher Filter in die Einoder Ausgabe geschaltet werden:
Eingabe
Datei
FileInputStream
MyFilterInputStream
Ausgabe
Datei
FileOutputStream
copy(from, to)
Prof. Dr. Nikolaus Wulff
13
Ein HTML Filter
• Ein einfacher HTML zu Text Konverter soll entwickelt
werden.
• Hierzu wird ein Filter verwendet, der alle HTML
Markup Tags elemeniert.
• Da es sich hierbei um reinen Text handelt ist es
einfacher mit einem Reader/Writer Paar zu arbeiten:
Eingabe
Datei
FileReader
Ausgabe
Datei
FileWriter
Prof. Dr. Nikolaus Wulff
HTMLReader
copy(from, to)
14
BufferedReader überladen
• Um einen CharakterFilter zu entwickeln bietet es
sich an von BufferedReader zu erben und dessen
read-Methode zu überladen.
• Die gesamte Funktionalität eines (gepufferten)
Readers ist dann bereits vorhanden.
• Es wird lediglich eine Methode implementiert, die
die HTML Auszeichnungen <xxx> herausfiltert.
• Eine „gute“ Implementierung würde eventuell noch
mehr leisten und z. B. an den richtigen Stellen
Zeilenumbrüche einbauen etc...
public class HTMLReader extends BufferedReader
{...}
Prof. Dr. Nikolaus Wulff
15
Gefiltertes read
public int read(char[] buf, int start, int len) throws IOException {
int i, j, num = 0;
boolean markup = false;
while(num == 0) {
num = super.read(buf, start, len);
if (num == EOF) return EOF;
i = j = start;
for(; i < start + num; i++) {
switch( buf[i]) {
case '<': markup = true;
break;
case '>': markup = false;
break;
default: if(!markup) buf[j++] = buf[i];
} // end switch
} // for loop
num = j - start;
} // while loop
return num;
}
Prof. Dr. Nikolaus Wulff
16
Java Persistenz
• Im IO Paket befindet sich die Serializable Schnittstelle.
• Serializable ist ein leeres Marker Interface.
• Klassen die diese Schnittstelle implementieren können von der JVM
automatisch in einem Stream serialisiert und somit per TCP/IP
verschickt oder im Dateisystem gespeichert und wieder ausgelesen
werden.
• Java verwendet hierzu die von Object geerbten Methoden
read/writeObject.
• Jedes Objekt lässt sich in einen ObjectOutputStream schreiben
oder von einem ObjectInputStream lesen.
Prof. Dr. Nikolaus Wulff
17
Übung
• Erweitern Sie das Painter und Shapes Beispiel, so
dass der Painter die Shapes in eine Datei schreiben
oder wieder auslesen kann.
– Geben Sie den Shapes mehr Attribute
• posX, posY, width, height
– Speichern/Lesen Sie in/aus "Paintable.dat"
– Geben Sie die Datei mit dem DOS Type Befehl auf der
Console aus. Was sehen Sie?
– Was passiert wenn eine der Shapes Klassen nicht
Serializable implementiert?
Prof. Dr. Nikolaus Wulff
18
Tip:
Painter
(from painter)
ObjectOutputStream
(from j av a. io)
ObjectInputStream
writeAll
drawAll()
addPaintable()
storeAll()
readAll()
readAll
(from j av a.io)
0..*
<<Interface>>
Paintable
<<Interface>>
Serializable
(from painter)
(from j av a.io)
Shape
(from shapes)
•
•
Lesen und Schreiben sind symmetrische Aktionen mit
korrepondierenden IO-Streams.
Das Serializable Marker-Interface wird am besten von der
abstrakten Shapes Klasse implementiert.
Prof. Dr. Nikolaus Wulff
19
Serialisierung in Aktion
public static void main(String[] args)
throws Exception {
Painter painter = new Painter();
addShapes(painter);
painter.drawAll();
System.out.println("");
String fileName = "Paintable.dat";
// store graph to file system
System.out.println("Store to " + fileName);
painter.storeAll(fileName);
// now create an empty fresh painter
Painter emptyPainter = new Painter();
System.out.println("");
System.out.println("Read from " + fileName);
emptyPainter.readAll(fileName);
emptyPainter.drawAll();
Prof. Dr. Nikolaus Wulff
}
20
Systemeigenschaften
• Das java.util Paket enthält die Klasse Properties als
Erweiterung einer Hashtable (Map).
• In ihr werden System- oder Applikationseigenschaften hinterlegt.
• Properties werden häufig als Textdateien gepflegt, um eine
Anwendung zu parametrisieren - ohne neu compilieren zu müssen.
• Properties lassen sich per In-/OutStream einfach (lesbar!)
serialisieren.
• Die java.lang.System Klasse liefert z.B. per
getProperties die aktuellen Umgebungsvariablen der JVM.
Properties props = System.getProperties();
Prof. Dr. Nikolaus Wulff
21
Eine Property Datei
# -------------------------------------------------# general server settings
# -------------------------------------------------server.url
= localhost
server.protocol = http
server.port
= 80
# -------------------------------------------------# available services
# -------------------------------------------------service.1.name = HelloWorld
service.1.class = services.HelloWorldService
service.1.param = DummyParameter
#
service.2.name = Calculator
service.2.class = services.CalculatorService
•
Obiges Beispiel zeigt die Struktur einer Property Datei. Sie besteht aus
(key,value)-Tupeln mit dem Kommentarzeichen #.
• Aufgrund des einfachen Aufbaus lässt sich diese Struktur ideal in einer
Map/Collection Klasse speichern...
Prof. Dr. Nikolaus Wulff
22
Übung
•
Schreiben Sie ein Programm, das die Systemeinstellungen auf der
Console ausgibt und auf Wunsch in einer Datei speichert. Was bedeuten
die Eigenschaften?
• Systemeinstellungen lassen sich beim Start der JVM per Kommandozeile
java -Dkey=value übergeben. Probieren sie dies aus.
– Tip: versuchen Sie einmal java -help
• Erweitern Sie die Klasse, so dass diese eine beliebige Property Datei
wieder einliest und ausgibt.
Prof. Dr. Nikolaus Wulff
23
Properties einlesen
• Eigenschaften lassen sich von beliebigen
InputStreams einlesen:
protected Properties loadInput(String name) {
Properties props = new Properties();
try {
InputStream fin = new FileInputStream(name);
props.load(fin);
} catch (Exception error) {
println("error reading " + name);
error.printStackTrace();
}
return props;
}
Prof. Dr. Nikolaus Wulff
24
Properties schreiben
• Ebenso leicht lassen sich diese in beliebige Ströme
schreiben:
protected void
storeOutput(Properties props,
String name) {
try {
OutputStream fout = new FileOutputStream(name);
props.store(fout, "Properties example");
} catch (Exception error) {
println("error writing " + name);
error.printStackTrace();
}
}
Prof. Dr. Nikolaus Wulff
25
Logging
• Häufig werden während der Entwicklung Debug Ausgaben per
System.out.println ausgegeben.
• Im Release Code sollen diese meistens nicht mehr erscheinen und
auch die Laufzeitumgebung nicht mehr unnötig mit String
Operationen belasten. Nur noch wichtige Fehlermeldungen müssen
protokolliert werden.
• Diese Funktionalität wird von Bibliotheken wie z.B. Log4J oder seit
JDK1.4 von dem java.util.logging Paket erfüllt.
• Debug Nachrichten lassen sich per Konfiguration aus einer Properties
Datei gezielt für einzelne Pakete oder Klassen gestaffelt nach der
Wichtigkeit (DEBUG, INFO, WARN, ERROR,...) an oder ausschalten
und in Dateien umleiten.
Prof. Dr. Nikolaus Wulff
26
Logging Example
import java.util.logging.Logger;
public class LoggingExample {
public static final boolean DEBUG = true;
/** create a logger associated to this class name */
private static Logger logger =
Logger.getLogger(LoggingExample.class.getName());
public void assertion(boolean cond, String reason) {
if (!cond) { // assertions logging will stay in production code
logger.severe("ASSERTION " + reason);
throw new IllegalStateException(reason);
}
}
public void doSomething(Object obj) {
if (DEBUG) { // no info logging in production code
logger.info("doing something with " + obj);
}
assertion(obj != null,"Object == null");
// do something useful ...
}
public static void main(String[] args) {
LoggingExample example = new LoggingExample();
example.doSomething(null);
}
}
Prof. Dr. Nikolaus Wulff
27
Tips zum Logging
• Da das DEBUG boolean als final static markiert ist, kann der
Compiler dies bereits auswerten und der gesamte Codeblock wird
nicht in die Class-Datei generiert, falls das Flag false ist. =>
Performance im Release!
• Damit nicht in allen Klassen DEBUG Flags gesetzt werden müssen,
das Flag pro Projekt/Bibliothek in eine zentrale Schnittstellendatei
auslagern. Diese wird an einer zentralen Stelle verwaltet:
import myproject.settings.Global;
public class LoggingExample {
public void doSomething(Object obj) {
if (Global.DEBUG) { // no info logging in production code
logger.info("doing something with " + obj);
}
assertion(obj != null,"Object == null");
// do something useful ...
}
Prof. Dr. Nikolaus Wulff
28
Logging Format
• Eigene LoggingFormatter können entwickelt und
definiert werden.
• Der Formatter der Log Ausgaben lässt sich in der
Logging.properties Datei parametrisieren.
• Optional kann er auch als Systemeigenschaft
definieren werden (funktioniert noch nicht):
-Djava.util.logging.ConsoleHandler.formatter=myFormatter
Prof. Dr. Nikolaus Wulff
29
Logging.properties
## From %JDK_HOME%\jre\lib\Logging.properties
handlers= java.util.logging.ConsoleHandler
# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
# Default global logging level.
.level= INFO
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
# java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.ConsoleHandler.formatter=logging.LogFormatter
Einbinden eines eigenen Formatierers
Prof. Dr. Nikolaus Wulff
30
Übung
• Entwickeln Sie einen LogFormatter der die Klasse und
Zeilenummer der Lognachricht mit ausgibt.
• Tip: Die Zeilennummer lässt sich aus dem Stacktrace einer
Exception ermitteln...
• Verwenden Sie anstatt des + Operators die Klasse
java.lang.StringBuffer, um Strings
zusammenzufügen.
Prof. Dr. Nikolaus Wulff
31
Stringparsing
• Häufig müssen zusammengesetzte Strings nach einem
bestimmten Schema zerlegt werden, z.B. CSV Dateien
(comma-separated-values).
• Im java.util Paket befindet sich die Klasse
StringTokenizer, die es gestattet String sehr
komfortabel in Teilausdrücke (Tokens) zu zerlegen.
String bigline = "this is a test";
StringTokenizer st = new StringTokenizer(bigline);
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
this
}
is
a
test
Prof. Dr. Nikolaus Wulff
32
Stringparsing
• Im Konstruktor kann das Trennungszeichen angeben
werden
• Voreinstellung ist das Leerzeichen (space)
' ' == '\s'
• Seit dem JDK1.4 gibt es in der String Klasse die Operation
split, die gleiches leistet und bevorzugt verwendet
werden soll. (Erfordert regular expression Syntax).
String[] result = bigline.split("\\s");
for (int x=0; x<result.length; x++)
System.out.println(result[x]);
Prof. Dr. Nikolaus Wulff
33
Übung
• Entwickeln Sie einen Parser, der den
Klassennamen einer beliebigen Klasse in die
einzelnen Pakete und die eigentliche Klasse
zerlegt.
• Denken Sie daran auch innere Klassen und
Interfaces mit auszugeben. Woran kann man diese
erkennen? Tip: Schauen Sie in das bin
Verzeichnis...
• Vergessen Sie den JUnit Test nicht.
Prof. Dr. Nikolaus Wulff
34
Übung
• Entwickeln und Testen Sie einen Parser, der einen HTTP GET request
in seine Bestandteile zerlegt.
• Ein solcher Request hat die generische Form
Request-Line = Method SP Request-URI SP HTTP-Version CRLF
• Die URI setzt sich aus dem Pfad und dem Dokument zusammen.
• Handelt es sich statt dessen um ein Servlet so können durch '?' und '&'
getrennt optionale Parameter übergeben werden.
Request-URI = /path/dokument
Request-URI = /name? arg1=val1 &arg2=val2 ...
GET /Calculator?arg1=5&arg2=3&op=+ HTTP/1.1
Prof. Dr. Nikolaus Wulff
35
Herunterladen