Eine praktische Anleitung zu DecimalFormat

Ein praktischer Leitfaden für DecimalFormat

1. Überblick

In diesem Artikel werden wir dieDecimalFormat-Klasse zusammen mit ihren praktischen Verwendungen untersuchen.

Dies ist eine Unterklasse vonNumberFormat, mit der die Darstellung derStringvon Dezimalzahlen unter Verwendung vordefinierter Muster formatiert werden kann.

Es kann auch umgekehrt verwendet werden, um Strings in Zahlen zu zerlegen.

2. Wie funktioniert es?

Um eine Zahl zu formatieren, müssen wir ein Muster definieren, bei dem es sich um eine Folge von Sonderzeichen handelt, die möglicherweise mit Text gemischt sind.

Es gibt 11 spezielle Musterzeichen, aber die wichtigsten sind:

  • 0 - Gibt eine Ziffer aus, falls angegeben, andernfalls 0

  • # - Gibt eine Ziffer aus, falls angegeben, sonst nichts

  • . - Geben Sie an, wo das Dezimaltrennzeichen platziert werden soll

  • , - Geben Sie an, wo das Gruppentrennzeichen platziert werden soll

Wenn das Muster auf eine Zahl angewendet wird, werden seine Formatierungsregeln ausgeführt und das Ergebnis wird gemäß denDecimalFormatSymbol derLocale unserer JVM gedruckt, sofern keine bestimmtenLocale angegeben sind.

Die Ausgaben der folgenden Beispiele stammen von einer JVM, die auf einem englischenLocaleausgeführt wird.

3. Grundlegende Formatierung

Lassen Sie uns nun sehen, welche Ausgaben beim Formatieren derselben Nummer mit den folgenden Mustern erzeugt werden.

3.1. Einfache Dezimalstellen

double d = 1234567.89;
assertThat(
  new DecimalFormat("#.##").format(d)).isEqualTo("1234567.89");
assertThat(
  new DecimalFormat("0.00").format(d)).isEqualTo("1234567.89");

Wie wir sehen können, wird der ganzzahlige Teil niemals verworfen, egal ob das Muster kleiner als die Zahl ist.

assertThat(new DecimalFormat("#########.###").format(d))
  .isEqualTo("1234567.89");
assertThat(new DecimalFormat("000000000.000").format(d))
  .isEqualTo("001234567.890");

Wenn das Muster stattdessen größer als die Zahl ist, werden Nullen hinzugefügt, während Hashes sowohl in der Ganzzahl als auch in den Dezimalteilen gelöscht werden.

3.2. Runden

Wenn der Dezimalteil des Musters nicht die gesamte Genauigkeit der eingegebenen Zahl enthalten kann, wird er gerundet.

Hier wurde der 0,89-Teil auf 0,90 gerundet, dann wurde die 0 fallengelassen:

assertThat(new DecimalFormat("#.#").format(d))
  .isEqualTo("1234567.9");

Hier wurde der 0,89-Teil auf 1,00 gerundet, dann wurde der 0,00-Teil fallengelassen und die 1 wurde zu der 7 summiert:

assertThat(new DecimalFormat("#").format(d))
  .isEqualTo("1234568");

Der Standardrundungsmodus istHALF_EVEN,, kann jedoch mit der MethodesetRoundingMode angepasst werden.

3.3. Gruppierung

Das Gruppentrennzeichen wird verwendet, um ein Untermuster anzugeben, das automatisch wiederholt wird:

assertThat(new DecimalFormat("#,###.#").format(d))
  .isEqualTo("1,234,567.9");
assertThat(new DecimalFormat("#,###").format(d))
  .isEqualTo("1,234,568");

3.4. Mehrere Gruppierungsmuster

Einige Länder haben eine variable Anzahl von Gruppierungsmustern in ihren Nummerierungssystemen.

Das indische Nummerierungssystem verwendet das Format,,. ##, in dem nur das erste Gruppentrennzeichen drei Zahlen enthält, während alle anderen zwei Zahlen enthalten.

Dies ist mit der KlasseDecimalFormatnicht möglich. Dabei wird nur das aktuellste Muster von links nach rechts beibehalten und auf die gesamte Zahl angewendet, wobei vorherige Gruppierungsmuster ignoriert werden.

Ein Versuch, das Muster,,,, zu verwenden, würde zu einer Umgruppierung auf, führen und zu einer Umverteilung auf,,, ## führen.

Um eine Übereinstimmung mit mehreren Gruppierungsmustern zu erreichen, müssen Sie unseren eigenen ManipulationscodeStringchreiben oder alternativ denIcu4J’s DecimalFormat ausprobieren, der dies ermöglicht.

3.5. String-Literale mischen

Es ist möglich,String Literale innerhalb des Musters zu mischen:

assertThat(new DecimalFormat("The # number")
  .format(d))
  .isEqualTo("The 1234568 number");

Es ist auch möglich, Sonderzeichen alsString-Literale zu verwenden, indem Sie Folgendes maskieren:

assertThat(new DecimalFormat("The '#' # number")
  .format(d))
  .isEqualTo("The # 1234568 number");

4. Lokalisierte Formatierung

Vielecountriesverwenden keine englischen Symbole und verwenden das Komma als Dezimaltrennzeichen und den Punkt als Gruppentrennzeichen.

Das Ausführen des,.-Musters auf einer JVM mit einem italienischenLocale würde beispielsweise 1,234,567,89 ausgeben.

Während dies in einigen Fällen eine nützliche i18n-Funktion sein kann, möchten wir in anderen möglicherweise ein bestimmtes, JVM-unabhängiges Format erzwingen.

So können wir das machen:

assertThat(new DecimalFormat("#,###.##",
  new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
  .isEqualTo("1,234,567.89");
assertThat(new DecimalFormat("#,###.##",
  new DecimalFormatSymbols(Locale.ITALIAN)).format(d))
  .isEqualTo("1.234.567,89");

Wenn dieLocale, an denen wir interessiert sind, nicht zu den vomDecimalFormatSymbols-Konstruktor abgedeckten gehören, können wir sie mit dergetInstance-Methode angeben:

Locale customLocale = new Locale("it", "IT");
assertThat(new DecimalFormat(
  "#,###.##",
   DecimalFormatSymbols.getInstance(customLocale)).format(d))
  .isEqualTo("1.234.567,89");

5. Wissenschaftliche Notationen

DasScientific Notation repräsentiert das Produkt einer Mantisse und eines Exponenten von zehn. Die Nummer 1234567.89 kann auch als 12.3456789 * 10 ^ 5 dargestellt werden (der Punkt wird um 5 Positionen verschoben).

5.1. E-Notation

Es ist möglich, eine Zahl in der wissenschaftlichen Notation mit dem MusterzeichenEauszudrücken, das den Exponenten von zehn darstellt:

assertThat(new DecimalFormat("00.#######E0").format(d))
  .isEqualTo("12.3456789E5");
assertThat(new DecimalFormat("000.000000E0").format(d))
  .isEqualTo("123.456789E4");

Wir sollten bedenken, dass die Anzahl der Zeichen nach dem Exponenten relevant ist. Wenn wir also 10 ^ 12 ausdrücken müssen, brauchen wirE00 und nichtE0.

5.2. Technische Notation

Es ist üblich, eine bestimmte Form der wissenschaftlichen Notation zu verwenden, die als technische Notation bezeichnet wird und die Ergebnisse anpasst, um als Vielfaches von drei ausgedrückt zu werden, beispielsweise wenn Maßeinheiten wie Kilo (10 ^ 3), Mega (10 ^ 6), Giga ( 10 ^ 9) und so weiter.

Wir können diese Art der Notation erzwingen, indem wir die maximale Anzahl ganzzahliger Ziffern (die mit dem # und links vom Dezimaltrennzeichen ausgedrückten Zeichen) so anpassen, dass sie höher als die minimale Anzahl (die mit der 0 ausgedrückte) und höher als ist 1.

Dies zwingt den Exponenten dazu, ein Vielfaches der maximalen Anzahl zu sein. Für diesen Anwendungsfall möchten wir, dass die maximale Anzahl drei ist:

assertThat(new DecimalFormat("##0.######E0")
  .format(d)).isEqualTo("1.23456789E6");
assertThat(new DecimalFormat("###.000000E0")
  .format(d)).isEqualTo("1.23456789E6");

6. Parsing

Lassen Sie uns sehen, wie es möglich ist,String mit der Analysemethode inNumber zu analysieren:

assertThat(new DecimalFormat("", new DecimalFormatSymbols(Locale.ENGLISH))
  .parse("1234567.89"))
  .isEqualTo(1234567.89);
assertThat(new DecimalFormat("", new DecimalFormatSymbols(Locale.ITALIAN))
  .parse("1.234.567,89"))
  .isEqualTo(1234567.89);

Da der zurückgegebene Wert nicht durch das Vorhandensein eines Dezimaltrennzeichens abgeleitet wird, können wir Methoden wie.doubleValue(),.longValue() des zurückgegebenenNumber-Objekts verwenden, um ein bestimmtes Grundelement in der Ausgabe zu erzwingen.

Wir können auch aBigDecimal wie folgt erhalten:

NumberFormat nf = new DecimalFormat(
  "",
  new DecimalFormatSymbols(Locale.ENGLISH));
((DecimalFormat) nf).setParseBigDecimal(true);

assertThat(nf.parse("1234567.89"))
  .isEqualTo(BigDecimal.valueOf(1234567.89));

7. Thread-Sicherheit

DecimalFormat isn’t thread-safe, daher sollten wir besonders darauf achten, wenn wir dieselbe Instanz zwischen Threads teilen.

8. Fazit

Wir haben die Hauptverwendungen derDecimalFormat-Klasse zusammen mit ihren Stärken und Schwächen. gesehen

Wie immer ist der vollständige Quellcodeover on Github verfügbar.