Een praktische gids voor DecimalFormat

1. Overzicht

In dit artikel gaan we de DecimalFormat klasse samen met zijn praktische toepassingen.

Dit is een subklasse van Nummer formaat, waarmee decimale getallen kunnen worden opgemaakt ' Draad representatie met behulp van voorgedefinieerde patronen.

Het kan ook omgekeerd worden gebruikt om strings in getallen te parseren.

2. Hoe werkt het?

Om een ​​getal op te maken, moeten we een patroon definiëren, een reeks speciale tekens die mogelijk met tekst worden gemengd.

Er zijn 11 speciale patroonkarakters, maar de belangrijkste zijn:

  • 0 - drukt een cijfer af, indien opgegeven, anders 0
  • # - drukt een cijfer af indien opgegeven, verder niets
  • . - geef aan waar het decimaalteken moet worden geplaatst
  • , - geef aan waar het scheidingsteken voor groepering moet worden geplaatst

Wanneer het patroon wordt toegepast op een getal, worden de opmaakregels uitgevoerd en wordt het resultaat afgedrukt volgens de DecimalFormatSymbol van onze JVM's Locale tenzij een specifiek Locale is gespecificeerd.

De uitvoer van de volgende voorbeelden is afkomstig van een JVM die op een Engelse versie draait Locale.

3. Basisopmaak

Laten we nu eens kijken welke uitvoer wordt geproduceerd bij het formatteren van hetzelfde nummer met de volgende patronen.

3.1. Eenvoudige decimalen

dubbele d = 1234567,89; assertThat (nieuw DecimalFormat ("#. ##"). format (d)). isEqualTo ("1234567.89"); assertThat (nieuwe DecimalFormat ("0.00"). format (d)). isEqualTo ("1234567.89"); 

Zoals we kunnen zien, wordt het gehele deel nooit weggegooid, ongeacht of het patroon kleiner is dan het getal.

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

Als het patroon in plaats daarvan groter is dan het getal, worden nullen toegevoegd, terwijl hashes worden verwijderd, zowel in het gehele getal als in de decimale delen.

3.2. Afronding

Als het decimale deel van het patroon niet de volledige precisie van het invoergetal kan bevatten, wordt het afgerond.

Hier is het .89-deel afgerond naar .90, daarna is de 0 verwijderd:

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

Hier is het .89-deel afgerond op 1,00, vervolgens is de .00 verwijderd en is de 1 opgeteld bij de 7:

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

De standaard afrondingsmodus is HALF_EVEN, maar het kan worden aangepast via de setRoundingMode methode.

3.3. Groepering

Het groeperingsteken wordt gebruikt om een ​​subpatroon op te geven dat automatisch wordt herhaald:

assertThat (nieuwe DecimalFormat ("#, ###. #"). format (d)) .isEqualTo ("1.234.567,9"); assertThat (nieuwe DecimalFormat ("#, ###"). format (d)) .isEqualTo ("1.234.568"); 

3.4. Meerdere groeperingspatronen

Sommige landen hebben een variabel aantal groeperingspatronen in hun nummeringsystemen.

Het Indiase nummeringssysteem gebruikt het formaat #, ##, ###. ##, waarbij alleen het eerste scheidingsteken voor groepen drie cijfers bevat, terwijl alle andere twee cijfers bevatten.

Dit is niet mogelijk met de DecimalFormat class, die alleen het laatste patroon bewaart dat van links naar rechts is aangetroffen, en het toepast op het hele getal, waarbij eerdere groeperingspatronen worden genegeerd.

Een poging om het patroon #, ##, ##, ##, ### te gebruiken, zou resulteren in een hergroepering naar #######, ### en eindigen in een herverdeling naar #, ###, # ##, ###.

Om meerdere groeperingspatronen te matchen, is het nodig om onze eigen te schrijven Draad manipulatiecode, of als alternatief om de Icu4J's te proberen DecimalFormat, wat dat mogelijk maakt.

3.5. String Literals mengen

Mixen is mogelijk Draad literals binnen het patroon:

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

Het is ook mogelijk om speciale tekens te gebruiken als Draad letterlijk, door te ontsnappen:

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

4. Gelokaliseerde opmaak

Veel landen gebruiken geen Engelse symbolen en gebruiken de komma als decimaal scheidingsteken en de punt als scheidingsteken voor groepen.

Het patroon #, ###. ## uitvoeren op een JVM met een Italiaan Localezou bijvoorbeeld 1.234.567,89 uitvoeren.

Hoewel dit in sommige gevallen een nuttige i18n-functie kan zijn, willen we in andere gevallen misschien een specifiek, JVM-onafhankelijk formaat afdwingen.

Hier is hoe we dat kunnen doen:

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

Als het Locale waarin we geïnteresseerd zijn, valt niet onder de DecimalFormatSymbols constructor, kunnen we het specificeren met de getInstance methode:

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

5. Wetenschappelijke notaties

De wetenschappelijke notatie vertegenwoordigt het product van een mantisse en een exponent van tien. Het nummer 1234567.89 kan ook worden weergegeven als 12.3456789 * 10 ^ 5 (de punt is 5 posities verschoven).

5.1. E.-Notatie

Het is mogelijk om een ​​getal in wetenschappelijke notatie uit te drukken met de E. patroonteken dat de exponent van tien vertegenwoordigt:

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

We moeten in gedachten houden dat het aantal tekens na de exponent relevant is, dus als we 10 ^ 12 moeten uitdrukken, hebben we E00 en niet E0.

5.2. Technische notatie

Het is gebruikelijk om een ​​bepaalde vorm van wetenschappelijke notatie te gebruiken, Engineering Notation genaamd, die resultaten aanpast om te worden uitgedrukt als een veelvoud van drie, bijvoorbeeld bij het gebruik van meeteenheden zoals Kilo (10 ^ 3), Mega (10 ^ 6), Giga ( 10 ^ 9), enzovoort.

We kunnen dit soort notatie afdwingen door het maximumaantal gehele getallen (de tekens uitgedrukt met de # en aan de linkerkant van het decimaalteken) aan te passen, zodat het hoger is dan het minimumaantal (dat wordt uitgedrukt met de 0) en hoger dan 1.

Dit dwingt de exponent om een ​​veelvoud te zijn van het maximale aantal, dus voor deze use-case willen we dat het maximale aantal drie is:

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

6. Ontleden

Laten we eens kijken hoe het mogelijk is om een Draad in een Aantal met de parse-methode:

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

Omdat de geretourneerde waarde niet wordt afgeleid uit de aanwezigheid van een decimaal scheidingsteken, kunnen we methoden gebruiken zoals .doubleValue (), .longValue () van de geretourneerde Aantal object om een ​​specifieke primitief in de uitvoer af te dwingen.

We kunnen ook een BigDecimal als volgt:

NumberFormat nf = nieuwe DecimalFormat ("", nieuwe DecimalFormatSymbols (Locale.ENGLISH)); ((DecimalFormat) nf) .setParseBigDecimal (true); assertThat (nf.parse ("1234567.89")) .isEqualTo (BigDecimal.valueOf (1234567.89)); 

7. Draad-veiligheid

DecimalFormat is niet draadveilig, dus moeten we speciale aandacht besteden aan het delen van dezelfde instantie tussen threads.

8. Conclusie

We hebben de belangrijkste toepassingen van de DecimalFormat klasse, samen met zijn sterke en zwakke punten.

Zoals altijd is de volledige broncode beschikbaar op Github.