Wie formatiert man eine Dezimalzahl?

Die Klasse DecimalFormat erweitert die abstrakte Klasse NumberFormat und stellt gemeinsam mit dieser eine Vielzahl an Funktionen zur Formatierung und Lokalisierung von Dezimalzahlen bereit.

Die lokale Variabilität dezimaler Zahlenformate nebst davon abgeleiteter Erscheinungsformen wie Prozentangaben, Währungsnotierungen, wissenschaftlicher Notation, etc., stellt eine Herausforderung bei der Internationalisierung von Programmen dar. Einerseits müssen unterschiedliche numerische Formate zur rechnerischen Verarbeitung vereinheitlicht werden, andererseits sollten numerische Werte in der jeweiligen Landesform dargestellt werden können.
Hierzu stellt Java die Klasse DecimalFormat bereit. Sie ist von NumberFormat abgeleitet und ermöglicht die Formulierung von Zeichenmustern, sog. Pattern, die die jeweilige syntaktische Erscheinung einer Dezimalzahl definieren. Ein solches Pattern besteht aus einer Abfolge festgelegter alphanumerischer Platzhalter, von denen die folgenden die wichtigsten sind1:

0 steht für eine zwingend anzuzeigende Ziffer innerhalb der darzustellenden Zahl; ist die Stelle leer, wird eine '0' dargestellt
# steht für eine optionale Ziffer innerhalb der darzustellenden Zahl; ist die Stelle leer, wird nichts dargestellt
. Dezimaltrenner
, Tausendertrenner, genauer: gruppiert die Ziffern zwischen ',' und '.' oder ',' und ','
- Minus-Zeichen

Mit Hilfe eines Patterns kann das Literal einer vorgegebenen Dezimalzahl in eine beliebige, z.B. auch lokalisierte Form überführt werden. Umgekehrt kann eine solche auch in die in Java gebräuchliche Standardform gewandelt werden.

import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;

public class ZahlenFormatieren {

    public static void main(String[] args) {
        double d = 12345.678;
        DecimalFormat df = new DecimalFormat("0,000,000.0#");
        String str = df.format(d);
        System.out.println(df.format(d)); // 0.012.345,68 
        try {
            System.out.println(df.parse(str));   // 12345.68
            System.out.println(df.parse("12345.678")); // 12345678
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

Im Beispiel wird ein DecimalFormat-Objekt erzeugt, dem ein Pattern-String an den Konstruktor übergeben wird [8]. Das Pattern weist neun obligatorische Stellen mit Tausendertrennern vor dem Komma und zwei Nachkommastellen auf. An die Methode format() des Formatters wird jedoch ein double-Wert mit drei Nachkommastellen und, da es sich um ein double-Literal und nicht um einen String handelt, selbstverständlich ohne Tausendertrenner, als Parameter übergeben. Die Methode liefert einen String, der dem initialen Pattern entspricht: Die Tausendertrenner werden verwendet und fehlende Ziffern mit '0' gefüllt [10].
Beachtenswert ist darüber hinaus, dass die drei Nachkommastellen patterngerecht auf zwei gekürzt und dabei gerundet werden. Die Rundung entspricht dabei in der Standardform dem Modus der Enumkonstante RoundingMode.HALF_EVEN. Soll ein davon abweichender verwendet werden, kann dies über die Methode DecimalFormat#setRoundingMode(RoundingMode mode) geändert werden.

Wird der formatierte Zahlenstring durch parse() wieder in die double-Normalform rückübersetzt, so wird als Dezimaltrenner wieder '.' verwendet und die Tausendertrenner entfallen, die Rundung bleibt jedoch erhalten [12].
Große Vorsicht ist angebracht, wenn durch den Formatter ein extern bereitgestellter String geparst wird. Entspricht dieser nicht dem vorgegebenen Pattern, so wird ab dem ersten falschen Zeichen jede Formatierung ignoriert [13]!

Ändern des Pattern-Zeicheninventars

Das Zeicheninventar der initialen Definition eines Patterns ist weitgehend eingeschränkt und richtet sich für die gängigsten Zeichen nach der o.a. Tabelle1. Durch die Klasse DecimalFormatSymbols lassen sich diese jedoch ändern, wie im Folgenden anhand des Dezimal- und des Tausendertrenners gezeigt.

DecimalFormat df = new DecimalFormat("0,000,000.0#");
DecimalFormatSymbols ds = new DecimalFormatSymbols();
ds.setGroupingSeparator('|');
ds.setDecimalSeparator('_');
df.setDecimalFormatSymbols(ds);
//...
System.out.println(df.format(d)); // 0|012|345_68

Regionale Pattern

Die Erzeugung des Patterns kann auch mittels einer Länderkonstante erzeugt werden. Hierzu muss jedoch statt eines DecimalFormat-Objektes eines seiner Superklasse NumberFormat erzeugt werden, das später zum DecimalFormat gecastet wird. Die Objektbildung findet über die Methode getInstance() statt. Ihr wird eine Konstante der Klasse Locale als Parameter übergeben.

NumberFormat nuf = NumberFormat.getInstance(Locale.JAPAN);
if (nuf instanceof DecimalFormat) {
    System.out.println(((DecimalFormat) nuf).toPattern()); // #,##0.###
}

1) Die vollständige Dokumentation des Patternaufbaus kann in den JavaDocs der Klasse DecimalFormat nachgeschlagen werden.

Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.