4.11 Ausgaben formatieren
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.
4.11.1 Formatieren und Ausgeben mit format()

Die Klasse String stellt mit der statischen Methode format() eine Möglichkeit bereit, Zeichenketten nach einer Vorgabe zu formatieren.
Beispiel |
String s = String.format( "Hallo %s. Es gab einen Anruf von %s.", |
Der erste an format() übergebene String nennt sich Format-String. Er enthält neben auszugebenden Zeichen weitere sogenannte 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 Vararg (oder alternativ das Feld direkt) mit den Werten, auf die sich die Format-Spezifizierer beziehen.
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 |
- 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 0 bis 16 hexadezimal aus: for ( int i = 0x0; i <= 0xf; i++ ) |
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 ist 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«. 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.26: 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++ ) |
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. Tabelle 4.21 gibt die wichtigsten Suffixe an, und weitere finden Sie in der API-Dokumentation. Alle Ausgaben berücksichtigen die gegebene Locale-Umgebung.
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 bzw. mit führenden Nullen (1–31 bzw. 01–31) |
%tk, %tl | Stundenangabe bezogen auf 24 bzw. 12 Stunden (0–23, 1–12) |
%tH, %tI | Zweistellige Stundenangabe bezogen auf 24 bzw. 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 in der Form %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.27: 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 ); |
4.11.2 Die Formatter-Klasse *

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.28: 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, das unser StringBuilder sein kann (es ist alles erlaubt, was vom Typ Appendable ist). Optimiert folgt somit:
Listing 4.29: 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 8.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.
4.11.3 Formatieren mit Masken *

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.30: 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. Das Sternchen * 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 des Musterplatzhalters ist.
Musterzeichen | Steht für |
* | jedes Zeichen |
# | eine Zahl, wie Character.isDigit()sie testet |
? | ein Zeichen nach Character.isLetter() |
A | ein Zeichen oder eine Ziffer, also Character.isLetter() oder Character.isDigit() |
U | ein Zeichen nach Character.isLetter(), aber konvertiert in einen Großbuchstaben |
L | ein Zeichen nach Character.isLetter(), aber konvertiert in einen Kleinbuchstaben |
H | ein Hexadezimalzeichen (0–9, a–f oder A–F) |
' | einen ausmaskierten und nicht interpretierten Bereich |
Weitere Möglichkeiten der Klasse beschreibt die API-Dokumentation.
4.11.4 Format-Klassen

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 eine andere Möglichkeit, 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.
Das folgende Beispiel zeigt einige Anwendungen zum zweiten Punkt.
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 ) |

Abbildung 4.11: 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.
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 ) ); |
Die Ausgabe ist: 2.000.000.000.000.000.000.000.000.000.000 |
abstract class java.text.Format |
- 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)
Liefert 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.
4.11.5 Zahlen, Prozente und Währungen mit NumberFormat und DecimalFormat formatieren *

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 |
- 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.31: 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.
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:
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 gibt es die beiden Fabrikfunktionen getInstance(Locale locale) und getInstance(String currencyCode). 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)
...
4.11.6 MessageFormat und Pluralbildung mit ChoiceFormat

MessageFormat ist eine besondere Unterklasse von Format, die für die Formulierung von Nachrichten gedacht ist. Die Klasse ist in etwa mit den Formatierungen über printf(), nur werden bei MessageFormat die Platzhalter immer per Index in geschweiften Klammern angesprochen.
Beispiel |
Formuliere einen Nachrichtenstring mit drei Feldern: int soldCars = 10; »10 Auto(s) verkauft am 01.07.2011 zum Gesamtpreis von 1.234.534.534,00 €.« Sie ist automatisch lokalisiert, die Sprache lässt sich jedoch wieder als Locale-Objekt übergeben. |
ChoiceFormat
Eine besondere Möglichkeit ist die Verbindung von MessageFormat und ChoiceFormat, um das Problem zu lösen, das unser Beispiel im Fall von verkauften Autos mit »Auto(s)« löst. Im Deutschen ist die Pluralbildung anspruchsvoll, da es »0 Autos, 1 Auto, 2 Autos, 3 Autos« usw. heißt aber nur »0 Koffer, 1 Koffer, 2 Koffer, ...«. Das in Software zu modellieren ist nicht ganz einfach, aber mit ChoiceFormat lässt es sich lösen. Dem Konstruktor werden zum Generieren der Ausgabe zwei Felder mitgegeben: Ein Limit-Array kodiert Bereiche, und ein zweites Feld enthält die zugeordneten Elemente für den Bereich.
Beispiel |
Löse das Problem mit »0 Autos, 1 Auto, 2 Autos« usw.: MessageFormat formatter = new MessageFormat( "Du hast {0} {1} verkauft." ); |
Object[] params = { size, size }; |
Die API-Dokumentation der Klasse ChoiceFormat gibt weitere Beispiele und zeigt insbesondere, wie sich die Bereiche auch in den Strings selbst kodieren lassen, was für externe Übersetzungsdateien optimal ist.
Ihr Kommentar
Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.