From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001 From: Sven Eisenhauer Date: Fri, 10 Nov 2023 15:11:48 +0100 Subject: add new repo --- .../hjp5/html/k100122.html | 1140 ++++++++++++++++++++ 1 file changed, 1140 insertions(+) create mode 100644 Master/Reference Architectures and Patterns/hjp5/html/k100122.html (limited to 'Master/Reference Architectures and Patterns/hjp5/html/k100122.html') diff --git a/Master/Reference Architectures and Patterns/hjp5/html/k100122.html b/Master/Reference Architectures and Patterns/hjp5/html/k100122.html new file mode 100644 index 0000000..aeb2188 --- /dev/null +++ b/Master/Reference Architectures and Patterns/hjp5/html/k100122.html @@ -0,0 +1,1140 @@ + + + +Handbuch der Java-Programmierung, 5. Auflage + + + + + + + + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage +
 <<  +  <   +  >   + >>  + API  +Kapitel 18 - Character-Streams +
+
+ + + + +

18.2 Ausgabe-Streams

+
+ +
+ + + + +

18.2.1 Die abstrakte Klasse Writer

+ +

+Basis aller sequenziellen Ausgaben ist die abstrakte Klasse Writer +des Pakets java.io, +die eine Schnittstelle für stream-basierte Ausgaben zur Verfügung +stellt: +

+ + + + + +
+ +
+protected Writer()
+
+public void close()
+public void flush()
+
+public void write(int c)
+public void write(char[] cbuf)
+abstract public void write(char[] cbuf, int off, int len)
+public void write(String str)
+public void write(String str, int off, int len)
+
+
+
+java.io.Writer
+ +

+Neben einem parameterlosen Konstruktor definiert sie die Methoden +close +und flush +und eine Reihe überladener write-Methoden. +Die Bedeutung des Konstruktors liegt darin, den Ausgabestrom zu öffnen +und für einen nachfolgenden Aufruf von write +vorzubereiten, bevor er schließlich mit close +wieder geschlossen wird. In der Grundform erwartet write +einen einzigen int-Parameter +und schreibt diesen als Byte in den Ausgabestrom. Daneben gibt es +weitere Varianten, die ein Array von Bytes oder ein String-Objekt +als Parameter erwarten und dieses durch wiederholten Aufruf der primitiven +write-Methode +ausgeben. Durch Aufruf von flush +werden eventuell vorhandene Puffer geleert und die darin enthaltenen +Daten an das Ausgabegerät weitergegeben. +

+ + + + + + + + + +
+ +

+Von abgeleiteten Klassen wird erwartet, dass sie mindestens die Methoden +flush +und close +sowie write(char, int, int) +überlagern. Aus Gründen der Performance ist es aber oftmals +sinnvoll, auch die übrigen write-Methoden +zu überlagern.

+ + + + +
 Hinweis 
+
+ + + + +

18.2.2 Auswahl des Ausgabegerätes

+ +

+Als abstrakte Basisklasse kann Writer +nicht instanziert werden. Statt dessen gibt es eine Reihe konkreter +Klassen, die aus Writer +abgeleitet wurden und deren Aufgabe es ist, die Verbindung zu einem +konkreten Ausgabegerät herzustellen oder Filterfunktionen zu +übernehmen. Tabelle 18.1 +gibt eine Übersicht dieser abgeleiteten Klassen. + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KlasseBedeutung
OutputStreamWriterBasisklasse für alle Writer, die einen +Character-Stream in einen Byte-Stream umwandeln
FileWriterKonkrete Ableitung von OutputStreamWriter +zur Ausgabe in eine Datei
FilterWriterAbstrakte Basisklasse für die Konstruktion +von Ausgabefiltern
PrintWriterAusgabe aller Basistypen im Textformat
BufferedWriterWriter zur Ausgabepufferung
StringWriterWriter zur Ausgabe in einen String +
CharArrayWriterWriter zur Ausgabe in ein Zeichen-Array +
PipedWriterWriter zur Ausgabe in einen PipedReader +
+

+Tabelle 18.1: Aus Writer abgeleitete Klassen

+ +

+In den folgenden Unterabschnitten werden die Klassen OutputStreamWriter, +FileWriter, +StringWriter +und CharArrayWriter +erläutert. Die Klassen BufferedWriter, +PrintWriter +und FilterWriter +sind Thema des nächsten Abschnitts. +

+ + + + + + + + + +
+ +

+Die Klasse PipedWriter +soll hier nicht erläutert werden. In Abschnitt 22.4.4 +findet sich jedoch ein Beispiel zur Anwendung der Klassen PipedInputStream +und PipedOutputStream, +das auf PipedReader +und PipedWriter +übertragbar ist.

+ + + + +
 Hinweis 
+
+ + + + +

OutputStreamWriter und FileWriter

+ +

+Die Klasse OutputStreamWriter +ist die Basisklasse für alle Writer, die eine Konvertierung zwischen +Character- und Byte-Streams vornehmen. Sie enthält ein Objekt +des Typs CharToByteConverter +(aus dem undokumentierten Paket sun.io), +das die Konvertierung der Ausgabezeichen bei allen schreibenden Zugriffen +vornimmt. Als übergeordnete Basisklasse ist OutputStreamWriter +für uns allerdings nicht so interessant wie die daraus abgeleitete +Klasse FileWriter, +die die Ausgabe in eine Datei ermöglicht. Sie implementiert die +abstrakten Eigenschaften von Writer +und bietet vier zusätzliche Konstruktoren, die es erlauben, eine +Datei zu öffnen: +

+ + + + + +
+ +
+public FileWriter(String fileName)
+  throws IOException
+
+public FileWriter(String fileName, boolean append)
+  throws IOException
+
+public FileWriter(File file)
+  throws IOException
+
+public FileWriter(FileDescriptor fd)
+
+
+
+java.io.FileWriter
+ +

+Am einfachsten kann eine Datei göffnet werden, indem der Dateiname +als String-Parameter +fileName übergeben wird. +Falls fileName eine bereits +vorhandene Datei bezeichnet, wird sie geöffnet und ihr bisheriger +Inhalt gelöscht, andernfalls wird eine neue Datei mit diesem +Namen angelegt. Sukzessive Aufrufe von write +schreiben weitere Bytes in diese Datei. Wird zusätzlich der Parameter +append mit dem Wert true +an den Konstruktor übergeben, so werden die Ausgabezeichen an +die Datei angehängt, falls sie bereits existiert. + +

+Das folgende Programm erstellt eine Datei hallo.txt +und schreibt die Zeile »Hallo JAVA« in die Datei: + + +

+ + + + + +
+ +
+001 /* Listing1801.java */
+002 
+003 import java.io.*;
+004 
+005 public class Listing1801
+006 {
+007   public static void main(String[] args)
+008   {
+009     String hello = "Hallo JAVA\r\n";
+010     FileWriter f1;
+011 
+012     try {
+013       f1 = new FileWriter("hallo.txt");
+014       f1.write(hello);
+015       f1.close();
+016     } catch (IOException e) {
+017       System.out.println("Fehler beim Erstellen der Datei");
+018     }
+019   }
+020 }
+
+
+Listing1801.java
+ +Listing 18.1: Erstellen einer Datei

+ +

+Fast alle Methoden der Klassen OutputStreamWriter +und FileWriter +deklarieren die Ausnahme IOException, +die als allgemeine Fehleranzeige im Paket java.io +verwendet wird. IOException +kann von einer Vielzahl von Methoden ausgelöst werden und hat +dabei teilweise sehr unterschiedliche Bedeutungen. So bedeutet sie +beim Aufruf des Konstruktors, dass es nicht möglich war, die +Datei anzulegen, was wiederum eine ganze Reihe von Gründen haben +kann. Beim Aufruf von write +signalisiert sie einen Schreibfehler, und bei close +zeigt sie einen nicht näher spezifizierten I/O-Fehler an. + +

+In unserem Beispiel wurden alle Ausnahmen dieses Typs von einer einzigen +try-catch-Anweisung +behandelt. Falls eine differenziertere Fehlererkennung nötig +ist, macht es Sinn, für die unterschiedlichen I/O-Operationen +verschiedene try-catch-Anweisungen +vorzusehen. +

+ + + + + + + + + +
+ +

+Die anderen Konstruktoren von FileWriter +erwarten ein File-Objekt +bzw. ein Objekt vom Typ FileDescriptor. +Während wir auf die Klasse FileDescriptor +nicht näher eingehen werden, ist ein File +die Repräsentation einer Datei im Kontext ihres Verzeichnisses. +Wir werden später in Kapitel 21 +darauf zurückkommen.

+ + + + +
 Hinweis 
+
+ + + + +

StringWriter und CharArrayWriter

+ +

+Die Klassen StringWriter +und CharArrayWriter +sind ebenfalls aus Writer +abgeleitet. Im Gegensatz zu FileWriter +schreiben sie ihre Ausgabe jedoch nicht in eine Datei, sondern in +einen dynamisch wachsenden StringBuffer +bzw. in ein Zeichenarray. + +

+StringWriter +besitzt zwei Konstruktoren: +

+ + + + + +
+ +
+public StringWriter()
+
+public StringWriter(int initialSize)
+
+
+
+java.io.StringWriter
+ +

+Der parameterlose Konstruktor legt einen StringWriter +mit der Standardgröße eines StringBuffer-Objekts +an, während der zweite Konstruktor es erlaubt, die initiale Größe +selbst festzulegen. Wie schon erwähnt, wächst der interne +Puffer automatisch, wenn fortgesetzte Aufrufe von write +dies erforderlich machen. Die schreibenden Zugriffe auf den Puffer +erfolgen mit den von Writer +bekannten write-Methoden. + +

+Für den Zugriff auf den Inhalt des Puffers stehen die Methoden +getBuffer +und toString +zur Verfügung: +

+ + + + + +
+ +
+public StringBuffer getBuffer()
+
+public String toString()
+
+
+
+java.io.StringWriter
+ +

+Die Methode getBuffer +liefert den internen StringBuffer, +während toString +den Puffer in einen String +kopiert und diesen an den Aufrufer liefert. + +

+Die Klasse CharArrayWriter +arbeitet ähnlich wie StringWriter, +schreibt die Zeichen allerdings in ein Character-Array. Analog zu +StringWriter +wächst dieses automatisch bei fortgesetzten Aufrufen von write. +Die Konstruktoren haben dieselbe Struktur wie bei StringWriter, +und auch die dort verfügbaren write-Methoden +stehen allesamt hier zur Verfügung: +

+ + + + + +
+ +
+public CharArrayWriter()
+
+public CharArrayWriter(int initialSize)
+
+
+
+java.io.CharArrayWriter
+ +

+Auf den aktuellen Inhalt des Arrays kann mit Hilfe der Methoden toString +und toCharArray +zugegriffen werden: +

+ + + + + +
+ +
+public String toString()
+
+public char[] toCharArray()
+
+
+
+java.io.CharArrayWriter
+ +

+Zusätzlich stehen die Methoden reset +und size +zur Verfügung, mit denen der interne Puffer geleert bzw. die +aktuelle Größe des Zeichen-Arrays ermittelt werden kann. +Durch Aufruf von writeTo +kann des weiteren der komplette Inhalt des Arrays an einen anderen +Writer +übergeben und so beispielsweise mit einem einzigen Funktionsaufruf +in eine Datei geschrieben werden: +

+ + + + + +
+ +
+public void reset()
+
+public int size()
+
+public void writeTo(Writer out)
+  throws IOException
+
+
+
+java.io.CharArrayWriter
+ + + + +

18.2.3 Schachteln von Ausgabe-Streams +

+ +

+Wie eingangs erwähnt, ist es in Java möglich, Streams zu +schachteln. Dazu gibt es die aus Writer +abgeleiteten Klassen BufferedWriter, +PrintWriter +und FilterWriter, +deren wesentlicher Unterschied zu Writer +darin besteht, dass sie als Membervariable einen zusätzlichen +Writer +besitzen, der im Konstruktor übergeben wird. Wenn nun die write-Methode +eines derart geschachtelten Writers aufgerufen wird, gibt sie die +Daten nicht direkt an den internen Writer +weiter, sondern führt zuvor erst die erforderlichen Filterfunktionen +aus. Damit lassen sich beliebige Filterfunktionen transparent realisieren. + + + + +

BufferedWriter

+ +

+Diese Klasse hat die Aufgabe, Stream-Ausgaben zu puffern. Dazu enthält +sie einen internen Puffer, in dem die Ausgaben von write +zwischengespeichert werden. Erst wenn der Puffer voll ist oder die +Methode flush +aufgerufen wird, werden alle gepufferten Ausgaben in den echten Stream +geschrieben. Das Puffern der Ausgabe ist immer dann nützlich, +wenn die Ausgabe in eine Datei geschrieben werden soll. Durch die +Verringerung der write-Aufrufe +reduziert sich die Anzahl der Zugriffe auf das externe Gerät, +und die Performance wird erhöht. + +

+BufferedWriter +besitzt zwei Konstruktoren: +

+ + + + + +
+ +
+public BufferedWriter(Writer out)
+
+public BufferedWriter(Writer out, int size)
+
+
+
+java.io.BufferedWriter
+ +

+In beiden Fällen wird ein bereits existierender Writer +übergeben, an den die gepufferten Ausgaben weitergereicht werden. +Falls die Größe des Puffers nicht explizit angegeben wird, +legt BufferedWriter +einen Standardpuffer an, dessen Größe für die meisten +Zwecke ausreichend ist. Die write-Methoden +von BufferedWriter +entsprechen denen der Klasse Writer. + +

+Zusätzlich gibt es eine Methode newLine, +mit der eine Zeilenschaltung in den Stream geschrieben werden kann. +Diese wird dem System-Property line.separator +entnommen und entspricht damit den lokalen Konventionen. + +

+Das nachfolgende Beispiel demonstriert die gepufferte Ausgabe einer +Reihe von Textzeilen in eine Datei buffer.txt: + + +

+ + + + + +
+ +
+001 /* Listing1802.java */
+002 
+003 import java.io.*;
+004 
+005 public class Listing1802
+006 {
+007   public static void main(String[] args)
+008   {
+009      Writer f1;
+010      BufferedWriter f2;
+011      String s;
+012 
+013      try {
+014        f1 = new FileWriter("buffer.txt");
+015        f2 = new BufferedWriter(f1);
+016        for (int i = 1; i <= 10000; ++i) {
+017          s = "Dies ist die " + i + ". Zeile";
+018          f2.write(s);
+019          f2.newLine();
+020        }
+021        f2.close();
+022        f1.close();
+023     } catch (IOException e) {
+024       System.out.println("Fehler beim Erstellen der Datei");
+025     }
+026   }
+027 }
+
+
+Listing1802.java
+ +Listing 18.2: Gepufferte Ausgabe in eine Datei

+ +

+Dieses Beispiel erzeugt zunächst einen neuen Writer +f1, um die Datei buffer.txt +anzulegen. Dieser wird anschließend als Parameter an den BufferedWriter +f2 übergeben, der dann für den Aufruf der Ausgaberoutinen +verwendet wird. +

+ + + + + + + + + + + +
+ +

+Die etwas umständliche Verwendung zweier Stream-Variablen läßt +sich vereinfachen, indem die Konstruktoren direkt beim Aufruf geschachtelt +werden. Das ist die unter Java übliche Methode, die auch zukünftig +bevorzugt verwendet werden soll:

+ + + + +
 Tipp 
+
+ + +

+ + + + + +
+ +
+001 /* Listing1803.java */
+002 
+003 import java.io.*;
+004 
+005 public class Listing1803
+006 {
+007   public static void main(String[] args)
+008   {
+009     BufferedWriter f;
+010     String s;
+011 
+012     try {
+013       f = new BufferedWriter(
+014          new FileWriter("buffer.txt"));
+015       for (int i = 1; i <= 10000; ++i) {
+016         s = "Dies ist die " + i + ". Zeile";
+017         f.write(s);
+018         f.newLine();
+019       }
+020       f.close();
+021     } catch (IOException e) {
+022       System.out.println("Fehler beim Erstellen der Datei");
+023     }
+024   }
+025 }
+
+
+Listing1803.java
+ +Listing 18.3: Schachteln von Writer-Konstruktoren

+ + + + +

PrintWriter

+ +

+Die stream-basierten Ausgaberoutinen in anderen Programmiersprachen +bieten meistens die Möglichkeit, alle primitiven Datentypen in +textueller Form auszugeben. Java realisiert dieses Konzept über +die Klasse PrintWriter, +die Ausgabemethoden für alle primitiven Datentypen und für +Objekttypen zur Verfügung stellt. PrintWriter +besitzt folgende Konstruktoren: +

+ + + + + +
+ +
+public PrintWriter(Writer out)
+
+public PrintWriter(Writer out, boolean autoflush)
+
+
+
+java.io.PrintWriter
+ +

+Der erste Konstruktor instanziert ein PrintWriter-Objekt durch Übergabe +eines Writer-Objekts, auf das die Ausgabe umgeleitet werden soll. +Beim zweiten Konstruktor gibt zusätzlich der Parameter autoflush +an, ob nach der Ausgabe einer Zeilenschaltung automatisch die Methode +flush +aufgerufen werden soll. + +

+Die Ausgabe von primitiven Datentypen wird durch eine Reihe überladener +Methoden mit dem Namen print +realisiert. Zusätzlich gibt es alle Methoden in einer Variante +println, +bei der automatisch an das Ende der Ausgabe eine Zeilenschaltung angehängt +wird. println +existiert darüber hinaus parameterlos, um lediglich eine einzelne +Zeilenschaltung auszugeben. Damit stehen folgende print-Methoden +zur Verfügung (analog für println): +

+ + + + + +
+ +
+public void print(boolean b)
+public void print(char c)
+public void print(char[] s)
+public void print(double d)
+public void print(float f)
+public void print(int i)
+public void print(long l)
+public void print(Object obj)
+public void print(String s)
+
+
+
+java.io.PrintWriter
+ +

+Das folgende Beispiel berechnet die Zahlenfolge 1 + 1/2 + 1/4 + ... +und gibt die Folge der Summanden und die aktuelle Summe unter Verwendung +mehrerer unterschiedlicher print-Routinen +in die Datei zwei.txt aus: + + +

+ + + + + +
+ +
+001 /* Listing1804.java */
+002 
+003 import java.io.*;
+004 
+005 public class Listing1804
+006 {
+007   public static void main(String[] args)
+008   {
+009     PrintWriter f;
+010     double sum = 0.0;
+011     int nenner;
+012 
+013     try {
+014       f = new PrintWriter(
+015           new BufferedWriter(
+016           new FileWriter("zwei.txt")));
+017 
+018       for (nenner = 1; nenner <= 1024; nenner *= 2) {
+019         sum += 1.0 / nenner;
+020         f.print("Summand: 1/");
+021         f.print(nenner);
+022         f.print("   Summe: ");
+023         f.println(sum);
+024       }
+025       f.close();
+026     } catch (IOException e) {
+027       System.out.println("Fehler beim Erstellen der Datei");
+028     }
+029   }
+030 }
+
+
+Listing1804.java
+ +Listing 18.4: Die Klasse PrintWriter

+ +

+Das Programm verwendet Methoden zur Ausgabe von Strings, Ganz- und +Fließkommazahlen. Nach Ende des Programms hat die Datei zwei.txt +folgenden Inhalt: + +

+Summand: 1/1   Summe: 1
+Summand: 1/2   Summe: 1.5
+Summand: 1/4   Summe: 1.75
+Summand: 1/8   Summe: 1.875
+Summand: 1/16   Summe: 1.9375
+Summand: 1/32   Summe: 1.96875
+Summand: 1/64   Summe: 1.98438
+Summand: 1/128   Summe: 1.99219
+Summand: 1/256   Summe: 1.99609
+Summand: 1/512   Summe: 1.99805
+Summand: 1/1024   Summe: 1.99902
+
+ +

+ + + + + + + + + + + +
+ +

+Das vorliegende Beispiel realisiert sogar eine doppelte Schachtelung +von Writer-Objekten. +Das PrintWriter-Objekt +schreibt in einen BufferedWriter, +der seinerseits in den FileWriter +schreibt. Auf diese Weise werden Datentypen im ASCII-Format gepuffert +in eine Textdatei geschrieben. Eine solche Schachtelung ist durchaus +üblich in Java und kann in einer beliebigen Tiefe ausgeführt +werden.

+ + + + +
 Tipp 
+
+ + + + +

FilterWriter

+ +

+Wie bereits mehrfach angedeutet, bietet die Architektur der Writer-Klassen +die Möglichkeit, eigene Filter zu konstruieren. Dies kann beispielsweise +durch Überlagern der Klasse Writer +geschehen, so wie es etwa bei PrintWriter +oder BufferedWriter +realisiert wurde. Der offizielle Weg besteht allerdings darin, die +abstrakte Klasse FilterWriter +zu überlagern. FilterWriter +besitzt ein internes Writer-Objekt +out, das bei der Instanzierung +an den Konstruktor übergeben wird. Zusätzlich überlagert +es drei der vier write-Methoden, +um die Ausgabe auf out umzuleiten. +Die vierte write-Methode +(write(String)) wird dagegen +nicht überlagert, sondern ruft gemäß ihrer Implementierung +in Writer +die Variante write(String, int, int) +auf. + +

+Soll eine eigene Filterklasse konstruiert werden, so ist wie folgt +vorzugehen: +

+ +

+Anschließend kann die neue Filterklasse wie gewohnt in einer +Kette von geschachtelten Writer-Objekten +verwendet werden. + +

+Wir wollen uns die Konstruktion einer Filterklasse anhand der folgenden +Beispielklasse UpCaseWriter +ansehen, deren Aufgabe es ist, innerhalb eines Streams alle Zeichen +in Großschrift zu konvertieren: + + +

+ + + + + +
+ +
+001 /* Listing1805.java */
+002 
+003 import java.io.*;
+004 
+005 class UpCaseWriter
+006 extends FilterWriter
+007 {
+008   public UpCaseWriter(Writer out)
+009   {
+010     super(out);
+011   }
+012 
+013   public void write(int c)
+014   throws IOException
+015   {
+016     super.write(Character.toUpperCase((char)c));
+017   }
+018 
+019   public void write(char[] cbuf, int off, int len)
+020   throws IOException
+021   {
+022     for (int i = 0; i < len; ++i) {
+023       write(cbuf[off + i]);
+024     }
+025   }
+026 
+027   public void write(String str, int off, int len)
+028   throws IOException
+029   {
+030     write(str.toCharArray(), off, len);
+031    }
+032 }
+033 
+034 public class Listing1805
+035 {
+036    public static void main(String[] args)
+037    {
+038       PrintWriter f;
+039       String s = "und dieser String auch";
+040 
+041       try {
+042          f = new PrintWriter(
+043              new UpCaseWriter(
+044              new FileWriter("upcase.txt")));
+045          //Aufruf von außen
+046          f.println("Diese Zeile wird schön groß geschrieben");
+047          //Test von write(int)
+048          f.write('a');
+049          f.println();
+050          //Test von write(String)
+051          f.write(s);
+052          f.println();
+053          //Test von write(String, int, int)
+054          f.write(s,0,17);
+055          f.println();
+056          //Test von write(char[], int, int)
+057          f.write(s.toCharArray(),0,10);
+058          f.println();
+059          //---
+060          f.close();
+061       } catch (IOException e) {
+062          System.out.println("Fehler beim Erstellen der Datei");
+063       }
+064    }
+065 }
+
+
+Listing1805.java
+ +Listing 18.5: Konstruktion einer eigenen FilterWriter-Klasse

+ +

+Im Konstruktor wird lediglich der Superklassen-Konstruktor aufgerufen, +da keine weiteren Aufgaben zu erledigen sind. Die drei write-Methoden +werden so überlagert, dass jeweils zunächst die Ausgabezeichen +in Großschrift konvertiert werden und anschließend die +passende Superklassenmethode aufgerufen wird, um die Daten an den +internen Writer +out zu übergeben. + +

+Der Test von UpCaseWriter erfolgt +mit der Klasse Listing1805. +Sie schachtelt einen UpCaseWriter +innerhalb eines FileWriter- +und eines PrintWriter-Objekts. +Die verschiedenen Aufrufe der write- +und println-Methoden +rufen dann jede der vier unterschiedlichen write-Methoden +des UpCaseWriter-Objekts mindestens +einmal auf, um zu testen, ob die Konvertierung in jedem Fall vorgenommen +wird. Die Ausgabe des Programms ist: + +

+DIESE ZEILE WIRD SCHÖN GROß GESCHRIEBEN
+A
+UND DIESER STRING AUCH
+UND DIESER STRING
+UND DIESER
+
+ +

+ + + + + + + + + + + +
+ +

+Wenn man sich die Implementierung der write-Methoden +von UpCaseWriter genauer ansieht, +könnte man auf die Idee kommen, dass sie wesentlich performanter +implementiert werden könnten, wenn nicht alle Ausgaben einzeln +an write(int) gesendet würden. +So scheint es nahezuliegen, beispielsweise write(String, +int, int) in der folgenden Form zu implementieren, denn +die Methode toUpperCase +existiert auch in der Klasse String:

+ + + + +
 Warnung 
+
+ +

+super.write(str.toUpperCase(), off, len);
+
+ + +

+Die Sache hat nur leider den Haken, dass String.toUpperCase +möglicherweise die Länge des übergebenen Strings verändert. +So wird beispielsweise das »ß« in ein »SS« +umgewandelt (an sich lobenswert!) und durch die unveränderlichen +Konstanten off und len +geht ein Zeichen verloren. Der hier beschrittene Workaround besteht +darin, grundsätzlich die Methode Character.toUpperCase +zu verwenden. Sie kann immer nur ein einzelnes Zeichen zurückgeben +und läßt damit beispielsweise ein »ß« bei +Umwandlung unangetastet. + +

+Als interessante Erkenntnis am Rande lernen wir dabei, dass offensichtlich +String.toUpperCase und Character.toUpperCase +unterschiedlich implementiert sind. Ein Blick in den Quellcode der +Klasse String +bestätigt den Verdacht und zeigt zwei Sonderbehandlungen, eine +davon für das »ß«, wie folgender Auszug aus dem +Quellcode des JDK 1.1 belegt (im JDK 1.2 sieht es ähnlich aus): + +

+for (i = 0; i < len; ++i) {
+   char ch = value[offset+i];
+   if (ch == '\u00DF') { // sharp s
+      result.append("SS");
+      continue;
+   }
+   result.append(Character.toUpperCase(ch));
+}
+
+ + +

+Im Umfeld dieser Methode sollte man also mit der nötigen Umsicht +agieren. Das Gegenstück lowerCase +hat diese Besonderheit übrigens nicht. +


+ + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 +
 <<  +  <   +  >   + >>  + API  +© 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de +
+ + + -- cgit v1.2.3