Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Eigene Klassen schreiben
6 Exceptions
7 Generics<T>
8 Äußere.innere Klassen
9 Besondere Klassen der Java SE
10 Architektur, Design und angewandte Objektorientierung
11 Die Klassenbibliothek
12 Bits und Bytes und Mathematisches
13 Datenstrukturen und Algorithmen
14 Threads und nebenläufige Programmierung
15 Raum und Zeit
16 Dateien, Verzeichnisse und Dateizugriffe
17 Datenströme
18 Die eXtensible Markup Language (XML)
19 Grafische Oberflächen mit Swing
20 Grafikprogrammierung
21 Netzwerkprogrammierung
22 Verteilte Programmierung mit RMI
23 JavaServer Pages und Servlets
24 Datenbankmanagement mit JDBC
25 Reflection und Annotationen
26 Dienstprogramme für die Java-Umgebung
A Die Begleit-DVD
Stichwort
Ihre Meinung?

Spacer
 <<   zurück
Java ist auch eine Insel von Christian Ullenboom
Das umfassende Handbuch
Buch: Java ist auch eine Insel

Java ist auch eine Insel
geb., mit DVD
1482 S., 49,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1506-0
Pfeil 4 Der Umgang mit Zeichenketten
  Pfeil 4.1 Einzelne Zeichen behandeln
    Pfeil 4.1.1 Von ASCII über ISO-8859-1 zu Unicode
    Pfeil 4.1.2 Die Character-Klasse
  Pfeil 4.2 Strings und deren Anwendung
    Pfeil 4.2.1 String-Literale als String-Objekte für konstante Zeichenketten
    Pfeil 4.2.2 String-Länge und Test auf Leerstring
    Pfeil 4.2.3 Nach enthaltenen Zeichen und Zeichenfolgen suchen
    Pfeil 4.2.4 Gut, dass wir verglichen haben
    Pfeil 4.2.5 Phonetische Vergleiche
    Pfeil 4.2.6 String-Teile extrahieren
    Pfeil 4.2.7 Strings anhängen, Groß-/Kleinschreibung und Leerraum
    Pfeil 4.2.8 Suchen und ersetzen
    Pfeil 4.2.9 String-Objekte mit Konstruktoren neu anlegen *
  Pfeil 4.3 Konvertieren zwischen Primitiven und Strings
    Pfeil 4.3.1 Unterschiedliche Typen in String-Repräsentationen konvertieren
    Pfeil 4.3.2 Stringinhalt in primitiven Wert konvertieren
    Pfeil 4.3.3 Unterschiedliche Ausgabeformate (Binär, Hex, Oktal) *
  Pfeil 4.4 Veränderbare Zeichenketten mit StringBuilder und StringBuffer
    Pfeil 4.4.1 Anlegen von StringBuilder/StringBuffer-Objekten
    Pfeil 4.4.2 StringBuilder/StringBuffer in andere Zeichenkettenformate konvertieren
    Pfeil 4.4.3 Daten anhängen
    Pfeil 4.4.4 Zeichen(folgen) setzen, erfragen, löschen und umdrehen
    Pfeil 4.4.5 Länge und Kapazität eines StringBuilder/StringBuffer-Objekts *
    Pfeil 4.4.6 Vergleichen von String mit StringBuilder und StringBuffer
    Pfeil 4.4.7 »hashCode()« bei StringBuilder/StringBuffer *
  Pfeil 4.5 CharSequence als Basistyp *
  Pfeil 4.6 Sprachabhängiges Vergleichen und Normalisierung *
    Pfeil 4.6.1 Die Klasse »Collator«
    Pfeil 4.6.2 Effiziente interne Speicherung für die Sortierung
    Pfeil 4.6.3 Normalisierung
  Pfeil 4.7 Reguläre Ausdrücke
    Pfeil 4.7.1 Arbeiten mit der Fassade: String#matches()
    Pfeil 4.7.2 Die Klassen Pattern und Matcher
    Pfeil 4.7.3 Finden und nicht matchen
    Pfeil 4.7.4 Gierige und nicht gierige Operatoren *
    Pfeil 4.7.5 Mit MatchResult alle Ergebnisse einsammeln *
    Pfeil 4.7.6 Suchen und Ersetzen mit Mustern
  Pfeil 4.8 Zerlegen von Zeichenketten
    Pfeil 4.8.1 Splitten von Zeichenketten mit »split()«
    Pfeil 4.8.2 Die Klasse Scanner
    Pfeil 4.8.3 Die Klasse StringTokenizer *
    Pfeil 4.8.4 BreakIterator als Zeichen-, Wort-, Zeilen- und Satztrenner *
  Pfeil 4.9 Zeichenkodierungen, XML/HTML-Entitys, Base64 *
    Pfeil 4.9.1 Unicode und 8-Bit-Abbildungen
    Pfeil 4.9.2 Konvertieren mit »OutputStreamWriter«-Klassen
    Pfeil 4.9.3 Das Paket »java.nio.charset«
    Pfeil 4.9.4 XML/HTML-Entitys ausmaskieren
    Pfeil 4.9.5 Base64-Kodierung
  Pfeil 4.10 Ausgaben formatieren
    Pfeil 4.10.1 Formatieren und Ausgeben mit »format()«
    Pfeil 4.10.2 Die Formatter-Klasse *
    Pfeil 4.10.3 Formatieren mit Masken *
    Pfeil 4.10.4 Format-Klassen
    Pfeil 4.10.5 Zahlen, Prozente und Währungen mit »NumberFormat« und »DecimalFormat« formatieren *
  Pfeil 4.11 Zum Weiterlesen


Rheinwerk Computing - Zum Seitenanfang

4.10 Ausgaben formatieren  Zur nächsten ÜberschriftZur vorigen Überschrift

Immer wieder müssen Zahlen, Datumsangaben und Text auf verschiedenste Art und Weise formatiert werden. Zur Formatierung bietet Java mehrere Lösungen:

  • Seit Java 5 realisieren die format()- und printf()-Methoden eine Ausgabe, so wie sie unter C mit printf() gesetzt wurde.
  • Formatieren über Format-Klassen: Allgemeines Formatierungsverhalten wird in einer abstrakten Klasse Format fixiert; konkrete Unterklassen, wie NumberFormat und DateFormat, nehmen sich spezielle Datenformate vor.
  • Umsetzung eines Strings nach einer gegebenen Maske mit einem MaskFormatter.
  • Die Format-Klassen bieten nicht nur landes- beziehungsweise sprachabhängige Ausgaben per format(), sondern auch den umgekehrten Weg, Zeichenketten wieder in Typen wie double oder Date zu zerlegen. Jede Zeichenkette, die vom Format-Objekt erzeugt wurde, kann auch mit dem Parser wieder eingelesen werden.

Rheinwerk Computing - Zum Seitenanfang

4.10.1 Formatieren und Ausgeben mit »format()«  Zur nächsten ÜberschriftZur vorigen Überschrift

Die Klasse String stellt mit der statischen Methode format() eine Möglichkeit bereit, Zeichenketten nach einer Vorgabe zu formatieren:

String s = String.format( "Hallo %s. Es gab einen Anruf von %s.", "Chris", "Joy" );
System.out.println( s );    // Hallo Chris. Es gab einen Anruf von Joy.

Der erste übergebene String nennt sich Format-String. Er enthält neben auszugebenden Zeichen weitere so genannte Format-Spezifizierer, die dem Formatierer darüber Auskunft geben, wie er das Argument formatieren soll. %s steht für eine unformatierte Ausgabe eines Strings. Nach dem Format-String folgt ein Varags (oder alternativ das Feld direkt) mit den Werten, auf die sich die Format-Spezifizierer beziehen.


Tabelle 4.12  Die wichtigsten Format-Spezifizierer im Überblick

Spezifizierer Steht für ... Spezifizierer Steht für ...

%n

neue Zeile

%b

Boolean

%%

Prozentzeichen

%s

String

%c

Unicode-Zeichen

%d

Dezimalzahl

%x

Hexadezimalschreibweise

%t

Datum und Zeit

%f

Fließkommazahl

%e

wissenschaftliche Notation



Tipp Der Zeilenvorschub ist vom Betriebssystem abhängig, und %n gibt uns ein gutes Mittel an die Hand, um an dieses Zeilenvorschubzeichen (oder diese Zeichenfolge) zu kommen. Dann kommt der format()-Aufruf auch mit einem Argument aus, und es lautet String.format("%n").



final class java.lang.String
implements CharSequence, Comparable<String>, Serializable

  • static String format( String format, Object... args ) Liefert einen formatierten String, der aus dem String und den Argumenten hervorgeht.
  • static String format( Locale l, String format, Object... args ) Liefert einen formatierten String, der aus der gewünschten Sprache, dem String und den Argumenten hervorgeht.

Intern werkeln java.util.Formatter (keine java.text.Format-Objekte), die sich auch direkt verwenden lassen; dort ist auch die Dokumentation festgemacht.

System.out.printf()

Soll eine mit String.format() formatierte Zeichenkette gleich ausgegeben werden, so muss dazu nicht System.out.print(String.format(format, args)); angewendet werden. Praktischerweise findet sich zum Formatieren und Ausgeben die aus String bekannte Methode format() auch in den Klassen PrintWriter und PrintStream (das System.out-Objekt ist vom Typ PrintStream). Da jedoch der Methodenname format() nicht wirklich konsistent zu den anderen printXXX()-Methoden ist, haben die Entwickler die format()-Methoden auch unter dem Namen printf() zugänglich gemacht (die Implementierung von printf() ist eine einfache Weiterleitung zur Methode format()).


Beispiel Gib die Zahlen von 1 bis 10 aus. Die Zahlen 1 bis 9 sollen eine führende Null bekommen:

for ( int i = 1 ; i < 11; i++
  System.out.printf( "%02d%n", i );  // 01 02 … 10

Auch bei printf() ist als erstes Argument ein Locale möglich.

Pimp my String mit Format-Spezifizierern *

Die Anzahl der Format-Spezifizierer ist so groß und ihre weitere Parametrisierung so vielfältig, dass ein Blick in die API-Dokumentation auf jeden Fall nötig ist. Die wichtigsten Spezifizierer sind:

  • %n ergibt das beziehungsweise die Zeichen für den Zeilenvorschub, jeweils bezogen auf die aktuelle Plattform. Die Schreibweise ist einem harten \n vorzuziehen, da dies nicht das Zeilenvorschubzeichen der Plattform sein muss.
  • %% liefert das Prozentzeichen selbst, wie auch \\ in einem String den Backslash ausmaskiert.
  • %s liefert einen String, wobei null zur Ausgabe »null« führt. %S schreibt die Ausgabe groß.
  • %b schreibt ein Boolean, und zwar den Wert »true« oder »false« im Fall des Typs Boolean. Die Ausgabe ist immer »false« bei null und »true« bei anderen Typen wie Integer, String. %B schreibt den String groß.
  • %c schreibt ein Zeichen, wobei die Typen Character, Byte und Short erlaubt sind. %C schreibt das Zeichen in Großbuchstaben.
  • Für die ganzzahligen numerischen Ausgaben mit %d (Dezimal), %x (Hexadezimal), %o (Oktal) sind Byte, Short, Integer, Long und BigInteger erlaubt – %X schreibt die hexadezimalen Buchstaben groß.
  • Bei den Fließkommazahlen mit %f oder %e (%E), %g (%G), %a (%A) sind zusätzlich die Typen Float, Double und BigDecimal zulässig. Die Standardpräzision für %e, %E, %f sind sechs Nachkommastellen.
  • Im Fall von Datums-/Zeitangaben mit %t beziehungsweise %T sind erlaubt: Long, Calendar und Date. %t benötigt zwingend ein Suffix.
  • Den Hashcode schreibt %h beziehungsweise %H. Beim Wert null ist auch das Ergebnis »null«.

Zusätzliche Flags, etwa für Längenangaben und die Anzahl an Nachkommastellen, sind möglich und werden im folgenden Beispiel gezeigt:

Listing 4.30  PrintfDemo.java, main()

PrintStream o = System.out;

int i = 123;
o.printf( "|%d|%d|%n" ,       i, -i );   // |123|-123|
o.printf( "|%5d|%5d|%n" ,     i, -i );   // |  123| –123|
o.printf( "|%-5d|%-5d|%n" ,   i, -i );   // |123  |-123 |
o.printf( "|%+-5d|%+-5d|%n" , i, -i );   // |+123 |-123 |
o.printf( "|%05d|%05d|%n%n",  i, -i );   // |00123|-0123|

o.printf( "|%X|%x|%n", 0xabc, 0xabc );     // |ABC|abc|
o.printf( "|%04x|%#x|%n%n", 0xabc, 0xabc );// |0abc|0xabc|

double d = 12345.678;
o.printf( "|%f|%f|%n" ,         d, -d ); // |12345,678000| |-12345,678000|
o.printf( "|%+f|%+f|%n" ,       d, -d ); // |+12345,678000| |-12345,678000|
o.printf( "|% f|% f|%n" ,       d, -d ); // | 12345,678000| |-12345,678000|
o.printf( "|%.2f|%.2f|%n" ,     d, -d ); // |12345,68| |-12345,68|
o.printf( "|%,.2f|%,.2f|%n" ,   d, -d ); // |12.345,68| |-12.345,68|
o.printf( "|%.2f|%(.2f|%n",     d, -d ); // |12345,68| |(12345,68)|
o.printf( "|%10.2f|%10.2f|%n" , d, -d ); // |  12345,68| | –12345,68|
o.printf( "|%010.2f|%010.2f|%n",d, -d ); // |0012345,68| |-012345,68|

String s = "Monsterbacke";
o.printf( "%n|%s|%n", s );                 // |Monsterbacke|
o.printf( "|%S|%n", s );                   // |MONSTERBACKE|
o.printf( "|%20s|%n", s );                 // |        Monsterbacke|
o.printf( "|%-20s|%n", s );                // |Monsterbacke        |
o.printf( "|%7s|%n", s );                  // |Monsterbacke|
o.printf( "|%.7s|%n", s );                 // |Monster|
o.printf( "|%20.7s|%n", s );               // |             Monster|

Date t = new Date();
o.printf( "%tT%n", t );                    // 11:01:39
o.printf( "%tD%n", t );                    // 04/18/08
o.printf( "%1$te. %1$tb%n", t );           // 18. Apr

Im Fall von Fließkommazahlen werden diese nach dem Modus BigDecimal.ROUND_HALF_UP gerundet, sodass etwa System.out.printf("%.1f", 0.45); die Ausgabe 0,5 ergibt.

Aus den Beispielen lassen sich einige Flags ablesen, insbesondere bei Fließkommazahlen. Ein Komma steuert, ob Tausendertrenner eingesetzt werden. Ein + gibt an, ob immer ein Vorzeichen angegeben wird, und ein Leerzeichen besagt, ob dann bei positiven Zeichen ein Platz freibleibt. Eine öffnende Klammer setzt bei negativen Zahlen kein Minus, sondern setzt diese in Klammern.


Beispiel Gib die Zahlen von 1 bis 10 aus. Die Zahlen 1 bis 9 sollen eine führende Null bekommen:

for ( int i = 1 ; i < 11; i++
  System.out.printf( "%02d%n", i );  // 01 02 … 10

Format-Spezifizierer für Datumswerte

Aus dem Beispiel wird ersichtlich, dass %t nicht einfach die Zeit ausgibt, sondern immer ein weiteres Suffix erwartet, das genau angibt, welcher Datums-/Zeitteil eigentlich gewünscht ist. Die folgende Tabelle gibt die wichtigsten Suffixe an, und weitere finden Sie in der API-Dokumentation. Alle Ausgaben berücksichtigen die gegebene Locale-Umgebung.


Tabelle 4.13  Suffixe für Datumswerte

Symbol Beschreibung

%tA, %ta

vollständiger/abgekürzter Name des Wochentags

%tB, %tb

vollständiger/abgekürzter Name des Monatsnamens

%tC

zweistelliges Jahrhundert (00–99)

%te, %td

Monatstag numerisch ohne beziehungsweise mit führenden Nullen (1–31 beziehungsweise 01–31)

%tk, %tl

Stundenangabe bezogen auf 24 beziehungsweise 12 Stunden (0–23, 1–12)

%tH, %tI

zweistellige Stundenangabe bezogen auf 24 beziehungsweise 12 Stunden (00–23, 01–12)

%tj

Tag des Jahres (001–366)

%tM

zweistellige Minutenangabe (00–59)

%tm

zweistellige Monatsangabe (in der Regel 01–12)

%tS

zweistellige Sekundenangabe (00–59)

%tY

vierstellige Jahresangabe

%ty

die letzten beiden Ziffern der Jahresangabe (00–99)

%tZ

abgekürzte Zeitzone

%tZ

Zeitzone mit Verschiebung zur GMT

%tR

Stunden und Minuten in der Form %tH:%tM

%tT

Stunden/Minuten/Sekunden: %tH:%tM:%tS

%tD

Datum in der Form %tm/%td/%ty

%tF

ISO-8601-Format %tY-%tm-%td

%tc

komplettes Datum mit Zeit in der Form %ta %tb %td %tT %tZ %tY


Positionsangaben

Im vorangegangenen Beispiel lautete eine Zeile:

System.out.printf( "%te. %1$tb%n", t );     // 28. Okt

Die Angabe mit Position$ ist eine Positionsangabe, und so bezieht sich 1$ auf das erste Argument, 2$ auf das zweite und so weiter (interessant ist, dass hier die Nummerierung nicht bei null beginnt).

Die Positionsangabe im Formatstring ermöglicht zwei Dinge:

  • Wird, wie in dem Beispiel, das gleiche Argument mehrmals verwendet, ist es unnötig, es mehrmals anzugeben. So wiederholt printf("%te. %tb%n", t, t) das Argument t, was die Angabe einer Position vermeidet. Statt %te. %1$tb%n lässt sich natürlich auch %1$te. %1$tb%n schreiben, also auch für das erste Argument ausdrücklich die Position 1 vorschreiben.
  • Die Reihenfolge der Parameter kann immer gleich bleiben, aber der Formatstring kann die Reihenfolge später ändern.

Der zweite Punkt ist wichtig für lokalisierte Ausgaben. Dazu ein Beispiel: Eine Bildschirmausgabe soll den Vor- und Nachnamen in unterschiedlichen Sprachen ausgeben. Die Reihenfolge der Namensbestandteile kann jedoch unterschiedlich sein, und nicht immer steht in jeder Sprache der Vorname vor dem Nachnamen. Im Deutschen heißt es im Willkommenstext dann »Hallo Christian Ullenboom«, aber in der (erfundenen) Sprache Bwatuti hieße es »Jambo Ullenboom Christian«:

Listing 4.31  FormatPosition.java, main()

Object[] formatArgs = { "Christian", "Ullenboom" };

String germanFormat = "Hallo %1$s %2$s";
System.out.printf( germanFormat, formatArgs );
System.out.println();

String bwatutiFormat = "Jambo %2$s %1$s";
System.out.printf( bwatutiFormat, formatArgs );

Die Aufrufreihenfolge für Vor-/Nachname ist immer die gleiche, aber der Formatstring, der zum Beispiel extern aus einer Konfigurationsdatei oder Datenbank kommt, kann diese Reihenfolge ändern und so der Landessprache anpassen.


Tipp Bezieht sich ein nachfolgendes Formatelement auf das vorangehende Argument, so kann ein < gesetzt werden:

Calendar c1 = new GregorianCalendar( 1973, 2, 12 );
Calendar c2 = new GregorianCalendar( 1985, 8, 2 );
System.out.printf( "%te. %<tb %<ty, %2$te. %<tb %<ty%n",
                   c1,              c2 );     // 12. Mrz 73, 2. Sep 85

Die Angaben für Monat und Jahr beziehen sich jeweils auf die vorangehenden Positionen. So muss nur einmal c1 und c2 angegeben werden.



Rheinwerk Computing - Zum Seitenanfang

4.10.2 Die Formatter-Klasse *  Zur nächsten ÜberschriftZur vorigen Überschrift

Die Methoden format() und prinf() übernehmen die Aufbereitung nicht selbst, sondern delegieren sie an die Klasse java.util.Formatter. Das ist auch der Grund, warum die Dokumentation für die Formatspezifizierer nicht etwa an String.format() hängt, sondern an Formatter.

Ein Blick auf die Methode format() der Klasse String verrät, wie der Formatter ins Spiel kommt:

Listing 4.32  java.lang.String, format()

public static String format( String format, Object ... args )
{
  return new Formatter().format( format, args ).toString();
}

Ein Formatter übernimmt zwei Aufgaben. Er übernimmt zum einen die tatsächliche Formatierung, und zum anderen gibt er die formatierten Ausgaben an ein Ziel weiter. Wird der Formatter mit dem Standardkonstruktor aufgerufen, so baut er selbst das Ausgabeziel aus einem StringBuilder auf, den folgende format()-Aufrufe dann füllen. toString() vom Formatter ist so implementiert, dass es auf dem Ausgabeziel (also in unserem Fall dem StringBuilder) toString() aufruft.

Das Wissen um diesen Mechanismus ist für die Optimierung wichtig, um nicht zu viele Zwischenobjekte zu erzeugen. So führt die Schleife

StringBuilder sb = new StringBuilder();
for ( double d = 0; d <= 1; d += 0.1 )
{
  String s = String.format( "%.1f%n", d );
  sb.append( s );
}
System.out.println( sb );   // 0,1 0,2 ... 1,0

zu:

StringBuilder sb = new StringBuilder();
for ( double d = 0; d <= 1; d += 0.1 )
{
  String s = new Formatter().format( "%.1f%n", d ).toString();
  sb.append( s );
}
System.out.println( sb );   // 0,1 0,2 ... 1,0

Bei jedem Schleifendurchlauf wird also ein neuer Formatter aufgebaut. Intern entsteht damit ein neuer StringBuilder als Ziel für die formatierten Strings und schlussendlich über toString() ein String-Objekt. Nicht zu vergessen sind die internen char-Felder und der GC, der die Objekte wieder wegräumen muss.

Würden wir gleich das Ziel angeben, so könnte das viel effizienter werden. Dazu wird nicht der Standardkonstruktor von Formatter eingesetzt, der das Ziel mit einem neuen StringBuilder vorbestimmt, sondern ein eigenes Zielobjekt, was unser StringBuilder sein kann (es ist alles erlaubt, was vom Typ Appendable ist). Optimiert folgt somit:

Listing 4.33  FormatterDemo.java, main()

StringBuilder sb = new StringBuilder();
Formatter formatter = new Formatter( sb );

for ( double d = 0; d <= 1; d += 0.1 )
  formatter.format( "%.1f%n", d );

System.out.println( formatter );   // 0,1 0,2 ... 1,0

Wir weisen in der Schleife den Formatter an, die Formatierung vorzunehmen. Da dieser mit dem Ziel StringBuilder aufgebaut wurde, füllen die Zahlen nach und nach unseren StringBuilder. Temporäre Zwischenobjekte werden so minimiert. Zum Schluss wird der Formatter nach dem Ergebnis gefragt.

»Formattable« und »formatTo()«

Der Formatspezifizierer %s kann auf jedem Argumenttyp angewendet werden, denn durch die Varargs werden auch primitive Elemente zu Wrapper-Objekten (zu Wrapper-Klassen, siehe Abschnitt 9.2, »Wrapper-Klassen und Autoboxing«), die eine toString()-Methode haben. Nun kann es aber sein, dass toString() besonders implementiert werden muss und nicht unbedingt die Zeichenkette liefert, die für die Ausgabe gewünscht ist. Für diesen Fall berücksichtigt der Formatter einen besonderen Typ. Implementiert die Klasse die besondere Schnittstelle java.util.Formattable, so ruft der Formatter nicht die toString()-Methode auf, sondern formatTo(Formatter formatter, int flags, int width, int precision). Die API-Dokumentation liefert ein Beispiel.


Rheinwerk Computing - Zum Seitenanfang

4.10.3 Formatieren mit Masken *  Zur nächsten ÜberschriftZur vorigen Überschrift

Oftmals unterscheidet sich bei grafischen Oberflächen die Darstellung von Daten von dem tieferliegenden Datenmodell. Während ein Datum zum Beispiel intern als große Zahl vorliegt, soll der Anwender sie in der gewünschten Landessprache sehen können. Bei einigen Ausgaben kommen Trennzeichen in die Ausgabe, um sie für den Leser besser verständlich zu machen. Eine IP-Adresse enthält Punkte an ganz bestimmen Stellen, eine Telefonnummer trennt die Vorwahl vom Rest ab, und die Segmente eines Datums trennen in der Regel die Zeichen »/« oder »-«.

Für Formatierungen, bei denen ein Originalstring in einen Ausgabestring konvertiert wird und dabei neue Zeichen zur Ausgabe eingefügt werden, bietet die Java-API eine Klasse javax.swing.text.MaskFormatter. Die Swing-Klasse hilft bei der Formatierung und dem Parsen:

Listing 4.34  MaskFormatterDemo.java, main()

MaskFormatter mf = new MaskFormatter( "**-**-****" );
mf.setValueContainsLiteralCharacters( false );
String valueToString = mf.valueToString( "12031973" );
System.out.println( valueToString );       // 12-03-1973
Object stringToValue = mf.stringToValue( valueToString );
System.out.println( stringToValue );       // 12031973

Der Konstruktor von MaskFormatter bekommt ein Muster, wobei es Platzhalter gibt. Es steht * für ein Zeichen. Die Methode valueToString() bringt einen String in das Muster. Der gemusterte String wandelt stringToValue() wieder in das Original um.

Das Schöne ist, dass die Muster-Definitionen aus einer externen Quelle stammen können, ohne den Programmcode mit speziellen Formatierungsanweisungen zu verschmutzen. Neben * gibt es weitere Platzhalter, die erlaubte Zeichen eingrenzen, sodass bei der Umwandlung mit valueToString() eine ParseException ausgelöst wird, wenn das Zeichen nicht im Format vom Musterplatzhalter ist.


Tabelle 4.14  Musterplatzhalter

Musterzeichen Steht für

*

jedes Zeichen

#

eine Zahl, wie Character.isDigit()sie testet

?

Zeichen nach Character.isLetter()

A

Zeichen oder Ziffer, also Character.isLetter() oder Character.isDigit()

U

Zeichen nach Character.isLetter(), aber konvertiert in Großbuchstaben

L

Zeichen nach Character.isLetter(), aber konvertiert in Kleinbuchstaben

H

Hexadezimalzeichen (0–9, a–f oder A–F)

'

einen ausmaskierten und nicht interpretierten Bereich


Weitere Möglichkeiten der Klasse beschreibt die API-Dokumentation.


Rheinwerk Computing - Zum Seitenanfang

4.10.4 Format-Klassen  Zur nächsten ÜberschriftZur vorigen Überschrift

Die Methode format() formatiert Zahlen, Datumswerte und sonstige Ausgaben und benötigt wegen ihrer Komplexität eine Beschreibung von mehreren Bildschirmseiten. Dabei gibt es noch einen anderen Weg, für unterschiedliche Typen von zu formatierenden Werten eigene Klassen zu haben:

  • DateFormat: Formatieren von Datums-/Zeitwerten
  • NumberFormat: Formatieren von Zahlen
  • MessageFormat: Formatieren für allgemeine Programmmeldungen

Die Klassen haben gemeinsam, dass sie die abstrakte Klasse Format erweitern und so eine gemeinsame Schnittstelle haben. Jede dieser Klassen implementiert auf jeden Fall die Methode format() zur Ausgabe und zum Parsen, also zur Konvertierung vom String in das Zielobjekt, die Methode parseObject().

Zwei Gründe sprechen für den Einsatz der Format-Klassen:

  • Es gibt in String zwar eine format()-Methode, aber keine parseXXX()-Methode.
  • Die Format-Klassen liefern mit statischen getXXXInstance()-Methoden vordefinierte Format-Objekte, die übliche Standardausgaben erledigen, etwa gerundete Ganzzahlen, Prozente oder unterschiedlich genaue Datums-/Zeitangaben.

Abbildung 4.2  DateFormat, MessageFormat und NumberFormat erweitern die abstrakte Klasse Format. Die Unterklassen übernehmen die Ein-/Ausgabe für Datumsangaben, für allgemeine Programmmeldungen und für Zahlen.

Das folgende Beispiel zeigt einige Anwendungen zum zweiten Punkt.


Tabelle 4.15  Formatobjekte im Einsatz

Ergebnis Formatiert mit

02.09.2005

DateFormat.getDateInstance().format( new Date() )

15:25:16

DateFormat.getTimeInstance().format( new Date() )

02.09.2005 15:25:16

DateFormat.getDateTimeInstance().format( new Date() )

12.345,679

NumberFormat.getInstance().format( 12345.6789 )

12.345,68 €

NumberFormat.getCurrencyInstance().format( 12345.6789 )

12 %

NumberFormat.getPercentInstance().format( 0.123 )


Beim Einsatz von DateFormat.getDateInstance().format(date) berücksichtigt die Methode korrekt je nach Land die Reihenfolge von Tag, Monat und Jahr und das Trennzeichen. Bei einem String.format() über %t müssten die drei Segmente je nach Sprache in die richtige Reihenfolge gebracht werden, sodass die Variante über DateFormat besser ist.


Hinweis NumberFormat stellt die Zahlen nicht in Exponentialschreibweise dar, und standardmäßig ist die Anzahl an Nachkommastellen beschränkt:

System.out.println( NumberFormat.getInstance().format( 2E30 ) );
System.out.println( NumberFormat.getInstance().format( 2E-30 ) );

Die Ausgabe ist:

2.000.000.000.000.000.000.000.000.000.000
0


abstract class java.text.Format
implements Serializable, Cloneable

  • String format( Object obj ) Formatiert das Objekt obj und gibt eine Zeichenkette zurück.
  • abstract StringBuffer format( Object obj, StringBuffer toAppendTo, FieldPosition pos ) Formatiert ein Objekt und hängt den Text an den angegebenen StringBuffer an (eine Methode mit StringBuilder gibt es nicht). Kann die Zeichenkette nicht mit format() nach den Regeln des Format-Objekts ausgegeben werden, löst die Methode eine IllegalArgumentException aus. Ist die Formatierungsanweisung falsch, so gibt format() das Unicode-Zeichen \uFFFD zurück.
  • Object parseObject( String source ) Analysiert den Text von Anfang an.
  • abstract Object parseObject( String source, ParsePosition pos ) Der Text wird ab der Stelle pos umgewandelt. Konnte parseObject() die Zeichenkette nicht zurückübersetzen, so folgt eine ParseException. parseObject(String, ParsePosition) verändert das ParsePosition-Objekt nicht und gibt die null-Referenz zurück.
  • Object clone() Gibt eine Kopie zurück.

Die Mehrzahl der Format-Unterklassen implementiert statische Fabrikmethoden der Art:

  • static XXXFormat getYYYInstance() Liefert ein Formatierungsobjekt mit den Formatierungsregeln für das voreingestellte Land.
  • static XXXFormat getYYYInstance( Locale l ) Für ein Formatierungsobjekt mit den Formatierungsregeln für das angegebene Land. So erlauben die Unterklassen von Format es dem Benutzer auch, weitere Objekte zu erzeugen, die an die speziellen Sprachbesonderheiten der Länder angepasst sind.

Rheinwerk Computing - Zum Seitenanfang

4.10.5 Zahlen, Prozente und Währungen mit »NumberFormat« und »DecimalFormat« formatieren *  topZur vorigen Überschrift

NumberFormat widmet sich der Ausgabe von Zahlen. Dabei unterstützt die Klasse vier Typen von Ausgaben, für die es jeweils eine statische Fabrikmethode gibt.


abstract class java.text.NumberFormat
extends Format

  • static NumberFormat getNumberInstance() Liefert den einfachen Formatierer für Zahlen.
  • static NumberFormat getIntegerInstance() Liefert einen Formatierer, der den Nachkommateil abschneidet und rundet.
  • static NumberFormat getPercentInstance() Liefert einen Formatierer, der Fließkommazahlen über die format()-Methode im Bereich von 0 bis 1 annimmt und dann als Prozentzahl formatiert. Nachkommastellen werden abgeschnitten.
  • static NumberFormat getCurrencyInstance() Liefert einen Formatierer für Währungen, der ein Währungszeichen zur Ausgabe hinzufügt.

Die genannten vier statischen Methoden gibt es jeweils in der parameterlosen Variante und in der Variante mit einem Locale-Objekt, um etwa das Währungszeichen oder das Kommazeichen anzupassen.

Dezimalzahlformatierung mit »DecimalFormat«

DecimalFormat ist eine Unterklasse von NumberFormat und ermöglicht individuellere Anpassungen an die Ausgabe. Dem Konstruktor kann ein Formatierungsstring übergeben werden, sozusagen eine Vorlage, wie die Zahlen zu formatieren sind. Die Formatierung einer Zahl durch DecimalFormat erfolgt mit Rücksicht auf die aktuell eingestellte Sprache:

Listing 4.35  DecimalFormatDemo.java, main()

double d = 12345.67890;
DecimalFormat df = new DecimalFormat( "###,##0.00" );
System.out.println( df.format(d) );           // 12.345,68

Der Formatierungsstring kann eine Menge von Formatierungsanweisungen vertragen; im Beispiel kommen #, 0 und das Komma vor. Die beiden wichtigen Symbole sind jedoch 0 und #. Beide repräsentieren Ziffern. Der Unterschied tritt erst dann zutage, wenn weniger Zeichen zum Formatieren da sind, als im Formatierungsstring genannt werden.


Tabelle 4.16  Formatierungsanweisungen für »DecimalFormat«

Symbol Bedeutung

0

Repräsentiert eine Ziffer – ist die Stelle nicht belegt, wird eine Null angezeigt.

#

Repräsentiert eine Ziffer – ist die Stelle nicht belegt, bleibt sie leer, damit führende Nullen und unnötige Nullen hinter dem Komma nicht angezeigt werden.

.

Dezimaltrenner. Trennt Vor- und Nachkommastellen.

,

Gruppiert die Ziffern (eine Gruppe ist so groß wie der Abstand von »,« zu ».«).

;

Trennzeichen. Links davon steht das Muster für positive Zahlen, rechts davon das Muster für negative Zahlen.

-

das Standardzeichen für das Negativpräfix

%

Die Zahl wird mit 100 multipliziert und als Prozentwert ausgewiesen.

\u2030

Die Zahl wird mit 1.000 multipliziert und als Promillewert ausgezeichnet.

\u00A4

nationales Währungssymbol (€ für Deutschland)

\u00A4\u00A4

internationales Währungssymbol (EUR für Deutschland)

X

Alle anderen Zeichen – symbolisch X – können ganz normal benutzt werden.

'

Ausmaskieren von speziellen Symbolen im Präfix oder Suffix


Hier sehen wir ein Beispiel für die Auswirkungen der Formatanweisungen auf einige Zahlen:


Tabelle 4.17  Beispiel für verschiedene Formatanweisungen

Format Eingabezahl Ergebnis

0000

12

0012

0000

12,5

0012

0000

1234567

1234567

##

12

12

##

12.3456

12

##

123456

123456

.00

12.3456

12,35

.00

.3456

,35

0.00

.789

0,79

#.000000

12.34

12,340000

,###

12345678.901

12.345.679

#.#;(#.#)

12345678.901

12345678,9

#.#;(#.#)

-12345678.901

(12345678,9)

,###.## \u00A4

12345.6789

12.345,68 €

,#00.00 \u00A4\u00A4

-12345678.9

-12.345.678,90 EUR

,#00.00 \u00A4\u00A4

0.1

00,10 EUR


Währungen angeben und die Klasse »Currency«

Die NumberFormat-Klasse liefert mit getCurrencyInstance() ein Format-Objekt, das neben der Dezimalzahl auch noch ein Währungssymbol mit anzeigt. So liefert NumberFormat.getCurrencyInstance().format(12345.6789) dann 12.345,68 €, also automatisch mit einem Euro-Zeichen. Dass es ein Euro-Zeichen ist und kein Yen-Symbol, liegt einfach daran, dass Java standardmäßig das eingestellte Land »sieht« und daraus die Währung ableitet. Wenn wir explizit den Formatter mit einem Land initialisieren, etwa wie in

NumberFormat frmt1 = DecimalFormat.getCurrencyInstance( Locale.FRANCE );
System.out.println( frmt1.format( 12345.6789 ) );         // 12 345,68 €

so ist die Währung automatisch Euro (denn Frankreich nutzt den Euro); schreiben wir DecimalFormat.getCurrencyInstance(Locale.JAPAN), ist sie Yen, und wir bekommen ¥12,346 (es gibt standardmäßig keine Nachkommastellen beim Yen). Locale-Objekte repräsentieren immer eine Sprachregion.

DecimalFormat beziehungsweise schon die Oberklasse NumberFormat ermöglicht die explizite Angabe der Währung. In der Java-Bibliothek wird sie durch die Klasse java.util.Currency repräsentiert. NumberFormat liefert mit getCurrency() die eingestellte Currency, die zur Formatierung verwendet wird, und setCurrency() setzt sie neu. Das löst Szenarios, in denen etwa ein Euro-Zeichen die Währung darstellt, aber die Zahlenformatierung englisch ist, wie die folgenden Zeilen zeigen:

NumberFormat frmt = DecimalFormat.getCurrencyInstance( Locale.ENGLISH );
frmt.setCurrency( Currency.getInstance( "EUR" ) );
System.out.println( frmt.format( 12345.6789 ) );  // EUR12,345.68

Die Currency-Klasse bietet drei statische Methoden, die Currency-Objekte liefern. Da ist zum einen getAvailableCurrencies(), was ein Set<Currency> liefert, und zum anderen die beiden Fabrikfunktionen getInstance(Locale locale) und getInstance(String currency-Code). Currency-Objekte besitzen eine ganze Reihe von Objektfunktionen, die etwa den ISO-4217-Währungscode liefern oder den ausgeschriebenen Währungsnamen (und das auch noch in verschiedenen Sprachen, wenn gewünscht).

Folgendes Programm geht über alle Währungen und gibt die zentralen Informationen aus:

for ( Currency currency : Currency.getAvailableCurrencies() )
{
  System.out.printf( "%s, %s, %s (%s)%n",
                     currency.getCurrencyCode(),
                     currency.getSymbol(),
                     currency.getDisplayName(),
                     currency.getDisplayName(Locale.ENGLISH) );
}

Wir bekommen dann mehr als 200 Ausgaben, und die Ausgabe beginnt mit:

EGP, EGP, Ägyptisches Pfund (Egyptian Pound)
IQD, IQD, Irak Dinar (Iraqi Dinar)
GHS, GHS, Ghana Cedi (Ghana Cedi)
AFN, AFN, Afghani (Afghani)
MUR, MUR, Mauritius Rupie (Mauritius Rupee)
SGD, SGD, Singapur Dollar (Singapore Dollar)



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen. >> Zum Feedback-Formular
 <<   zurück
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Java ist auch eine Insel






 Java ist auch
 eine Insel


Zum Katalog: Java SE Bibliotheken






 Java SE Bibliotheken


Zum Katalog: Professionell entwickeln mit Java EE 7






 Professionell
 entwickeln mit
 Java EE 7


Zum Katalog: Einstieg in Eclipse






 Einstieg in
 Eclipse


Zum Katalog: Einstieg in Java






 Einstieg in
 Java


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2011
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de