Статьи

Java Числовое Форматирование: DecimalFormat

В публикации « Числовое форматирование Java» я описал и продемонстрировал некоторые полезные экземпляры, предоставляемые статическими методами NumberFormat, такие как NumberFormat.getNumberInstance (Locale) , NumberFormat.getPercentInstance (Locale) , NumberFormat.getCurrencyInstance (Locale) и NumberFormat.getIntegerInstance (Locale). ) Оказывается, что все эти экземпляры абстрактного NumberFormat на самом деле являются экземплярами DecimalFormat , который расширяет NumberFormat .

Следующий листинг кода и связанный с ним вывод демонстрируют, что все экземпляры, возвращаемые NumberFormat getInstance DecimalFormat самом деле DecimalFormat экземплярами DecimalFormat . Что отличает эти экземпляры одного и того же класса DecimalFormat это настройки их атрибутов, таких как минимальная и максимальная целые цифры (цифры слева от десятичной точки) и минимальное и максимальное количество дробных цифр (цифры справа от десятичной точки) , Все они имеют одинаковый режим округления и настройки валюты.

Экземпляры, предоставляемые NumberFormat.getInstance (), являются экземплярами DecimalFormat.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
 * Write characteristics of provided Currency object to
 * standard output.
 *
 * @param currency Instance of Currency whose attributes
 *    are to be written to standard output.
 */
public void printCurrencyCharacteristics(final Currency currency)
{
   out.print("\tCurrency: " + currency.getCurrencyCode()
      + "(ISO 4217 Code: " + currency.getNumericCode() + "), ");
   out.println(currency.getSymbol() + ", (" + currency.getDisplayName() + ")");
}
 
/**
 * Writes characteristics of provided NumberFormat instance
 * to standard output under a heading that includes the provided
 * description.
 *
 * @param numberFormat Instance of NumberFormat whose key
 *    characteristics are to be written to standard output.
 * @param description Description to be included in standard
 *    output.
 */
public void printNumberFormatCharacteristics(
   final NumberFormat numberFormat, final String description)
{
   out.println(description + ": " + numberFormat.getClass().getCanonicalName());
   out.println("\tRounding Mode:           " + numberFormat.getRoundingMode());
   out.println("\tMinimum Fraction Digits: " + numberFormat.getMinimumFractionDigits());
   out.println("\tMaximum Fraction Digits: " + numberFormat.getMaximumFractionDigits());
   out.println("\tMinimum Integer Digits:  " + numberFormat.getMinimumIntegerDigits());
   out.println("\tMaximum Integer Digits:  " + numberFormat.getMaximumIntegerDigits());
   printCurrencyCharacteristics(numberFormat.getCurrency());
   if (numberFormat instanceof DecimalFormat)
   {
      final DecimalFormat decimalFormat = (DecimalFormat) numberFormat;
      out.println("\tPattern: " + decimalFormat.toPattern());
   }
}
 
/**
 * Display key characteristics of the "standard"
 * NumberFormat/DecimalFormat instances returned by the static
 * NumberFormat methods getIntegerInstance(), getCurrencyInstance(),
 * getPercentInstance(), and getNumberInstance().
 */
public void demonstrateDecimalFormatInstancesFromStaticNumberFormatMethods()
{
   final NumberFormat integerInstance = NumberFormat.getIntegerInstance();
   printNumberFormatCharacteristics(integerInstance, "IntegerInstance");
   final NumberFormat currencyInstance = NumberFormat.getCurrencyInstance();
   printNumberFormatCharacteristics(currencyInstance, "CurrencyInstance");
   final NumberFormat percentInstance = NumberFormat.getPercentInstance();
   printNumberFormatCharacteristics(percentInstance, "PercentInstance");
   final NumberFormat numberInstance = NumberFormat.getNumberInstance();
   printNumberFormatCharacteristics(numberInstance, "NumberInstance");
}

numberFormatStaticProvidedInstancesAreDecimalFormatInstances

Хотя мой предыдущий пост и этот пост до сих пор демонстрировали получение экземпляров DecimalFormat через статические NumberFormat доступа NumberFormat , в DecimalFormat также есть три перегруженных конструктора DecimalFormat () , DecimalFormat (String) и DecimalFormat (String, DecimalFormatSymbols) . Однако обратите внимание, что в документации Javadoc для DecimalFormat есть предупреждение: «Как правило, не вызывайте конструкторы DecimalFormat напрямую, поскольку фабричные методы NumberFormat могут возвращать подклассы, отличные от DecimalFormat». Мои следующие несколько примеров DecimalFormat экземпляры DecimalFormat с их прямыми конструкторами, несмотря на это предупреждение Javadoc, потому что в этом случае это не повредит.

Экземпляры DecimalFormat поддерживают большую степень контроля над форматированием представления десятичных чисел. Следующий код запускает стандартный набор чисел, использованный в предыдущем примере, против множества различных пользовательских шаблонов. Снимок экрана после листинга кода показывает, как эти числа отображаются при применении этих шаблонов.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
 * Apply provided pattern to DecimalFormat instance and write
 * output of application of that DecimalFormat instance to
 * standard output along with the provided description.
 *
 * @param pattern Pattern to be applied to DecimalFormat instance.
 * @param description Description of pattern being applied.
 */
private void applyPatternToStandardSample(
   final String pattern, final String description)
{
   final DecimalFormat decimalFormat = new DecimalFormat(pattern);
   printHeader(description + " - Applying Pattern '" + pattern + "'");
   for (final double theDouble : ourStandardSample)
   {
      out.println(
         theDouble + ": " + decimalFormat.format(theDouble));
   }
}
 
/**
 * Demonstrate various String-based patters applied to
 * instances of DecimalFormat.
 */
public void demonstrateDecimalFormatPatternStringConstructor()
{
   final String sixFixedDigitsPattern = "000000";
   applyPatternToStandardSample(sixFixedDigitsPattern, "Six Fixed Digits");
   final String sixDigitsPattern = "###000";
   applyPatternToStandardSample(sixDigitsPattern, "Six Digits Leading Zeros Not Displayed");
   final String percentagePattern = "";
   applyPatternToStandardSample(percentagePattern, "Percentage");
   final String millePattern = "\u203000";
   applyPatternToStandardSample(millePattern, "Mille");
   final String currencyPattern = "\u00A4";
   applyPatternToStandardSample(currencyPattern, "Currency");
   final String internationalCurrencyPattern = "\u00A4";
   applyPatternToStandardSample(internationalCurrencyPattern, "Double Currency");
   final String scientificNotationPattern = "0.###E0";
   applyPatternToStandardSample(scientificNotationPattern, "Scientific Notation");
}
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
==================================================================
= Six Fixed Digits - Applying Pattern '000000'
==================================================================
NaN: �
0.25: 000000
0.4: 000000
0.567: 000001
1.0: 000001
10.0: 000010
100.0: 000100
1000.0: 001000
10000.0: 010000
100000.0: 100000
1000000.0: 1000000
1.0E7: 10000000
Infinity: ∞
==================================================================
= Six Digits Leading Zeros Not Displayed - Applying Pattern '###000'
==================================================================
NaN: �
0.25: 000
0.4: 000
0.567: 001
1.0: 001
10.0: 010
100.0: 100
1000.0: 1000
10000.0: 10000
100000.0: 100000
1000000.0: 1000000
1.0E7: 10000000
Infinity: ∞
==================================================================
= Percentage - Applying Pattern ''
==================================================================
NaN: �
0.25: %25
0.4: %40
0.567: %57
1.0: %100
10.0: %1000
100.0: %10000
1000.0: %100000
10000.0: %1000000
100000.0: %10000000
1000000.0: %100000000
1.0E7: %1000000000
Infinity: %∞
==================================================================
= Mille - Applying Pattern '‰00'
==================================================================
NaN: �
0.25: ‰250
0.4: ‰400
0.567: ‰567
1.0: ‰1000
10.0: ‰10000
100.0: ‰100000
1000.0: ‰1000000
10000.0: ‰10000000
100000.0: ‰100000000
1000000.0: ‰1000000000
1.0E7: ‰10000000000
Infinity: ‰∞
==================================================================
= Currency - Applying Pattern '¤'
==================================================================
NaN: �
0.25: $0
0.4: $0
0.567: $1
1.0: $1
10.0: $10
100.0: $100
1000.0: $1000
10000.0: $10000
100000.0: $100000
1000000.0: $1000000
1.0E7: $10000000
Infinity: $∞
==================================================================
= Double Currency - Applying Pattern '¤'
==================================================================
NaN: �
0.25: $0
0.4: $0
0.567: $1
1.0: $1
10.0: $10
100.0: $100
1000.0: $1000
10000.0: $10000
100000.0: $100000
1000000.0: $1000000
1.0E7: $10000000
Infinity: $∞
==================================================================
= Scientific Notation - Applying Pattern '0.###E0'
==================================================================
NaN: �
0.25: 2.5E-1
0.4: 4E-1
0.567: 5.67E-1
1.0: 1E0
10.0: 1E1
100.0: 1E2
1000.0: 1E3
10000.0: 1E4
100000.0: 1E5
1000000.0: 1E6
1.0E7: 1E7
Infinity: ∞

Для моих последних двух примеров применения DecimalFormat я DecimalFormat экземпляр DecimalFormat помощью предпочтительного подхода использования NumberFormat.getInstance (Locale) . Первый листинг кода демонстрирует разные локали, примененные к одному и тому же двойному символу, а затем формат вывода для каждого.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
 * Provides an instance of DecimalFormat based on the provided instance
 * of Locale.
 *
 * @param locale Locale to be associated with provided instance of
 *    DecimalFormat.
 * @return Instance of DecimalFormat associated with provided Locale.
 * @throws ClassCastException Thrown if the object provided to me
 *    by NumberFormat.getCurrencyInstance(Locale) is NOT an instance
 *    of class {@link java.text.DecimalFormat}.
 */
private DecimalFormat getDecimalFormatWithSpecifiedLocale(final Locale locale)
{
   final NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
   if (!(numberFormat instanceof DecimalFormat))
   {
      throw new ClassCastException(
         "NumberFormat.getCurrencyInstance(Locale) returned an object of type "
            + numberFormat.getClass().getCanonicalName() + " instead of DecimalFormat.");
   }
   return (DecimalFormat) numberFormat;
}
 
/**
 * Demonstrate formatting of double with various Locales.
 */
public void demonstrateDifferentLocalesCurrencies()
{
   final double monetaryAmount = 14.99;
   out.println("Locale-specific currency representations of " + monetaryAmount + ":");
   out.println("\tLocale.US:            "
      + getDecimalFormatWithSpecifiedLocale(Locale.US).format(monetaryAmount));
   out.println("\tLocale.UK:            "
      + getDecimalFormatWithSpecifiedLocale(Locale.UK).format(monetaryAmount));
   out.println("\tLocale.ENGLISH:       "
      + getDecimalFormatWithSpecifiedLocale(Locale.ENGLISH).format(monetaryAmount));
   out.println("\tLocale.JAPAN:         "
      + getDecimalFormatWithSpecifiedLocale(Locale.JAPAN).format(monetaryAmount));
   out.println("\tLocale.GERMANY:       "
      + getDecimalFormatWithSpecifiedLocale(Locale.GERMANY).format(monetaryAmount));
   out.println("\tLocale.CANADA:        "
      + getDecimalFormatWithSpecifiedLocale(Locale.CANADA).format(monetaryAmount));
   out.println("\tLocale.CANADA_FRENCH: "
      + getDecimalFormatWithSpecifiedLocale(Locale.CANADA_FRENCH).format(monetaryAmount));
   out.println("\tLocale.ITALY:         "
      + getDecimalFormatWithSpecifiedLocale(Locale.ITALY).format(monetaryAmount));
}
1
2
3
4
5
6
7
8
9
Locale-specific currency representations of 14.99:
 Locale.US:            $14.99
 Locale.UK:            £14.99
 Locale.ENGLISH:       ¤14.99
 Locale.JAPAN:         ¥15
 Locale.GERMANY:       14,99 €
 Locale.CANADA:        $14.99
 Locale.CANADA_FRENCH: 14,99 $
 Locale.ITALY:         € 14,99

Мои примеры DecimalFormat до сих пор были сосредоточены на форматировании чисел для представления. Этот последний пример идет в другом направлении и анализирует значение из строкового представления.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
/**
 * Demonstrate parsing.
 */
public void demonstrateParsing()
{
   final NumberFormat numberFormat = NumberFormat.getCurrencyInstance(Locale.US);
   final double value = 23.23;
   final String currencyRepresentation = numberFormat.format(value);
   out.println("Currency representation of " + value + " is " + currencyRepresentation);
   try
   {
      final Number parsedValue = numberFormat.parse(currencyRepresentation);
      out.println("Parsed value of currency representation " + currencyRepresentation + " is " + parsedValue);
   }
   catch (ParseException parseException)
   {
      out.println("Exception parsing " + currencyRepresentation + parseException);
   }
}
1
2
Currency representation of 23.23 is $23.23
Parsed value of currency representation $23.23 is 23.23

Последний показанный пример на самом деле не нуждался в доступе к конкретным методам DecimalNumber и мог использовать только методы NumberFormat -Advertised. Пример форматирует представление валюты с помощью NumberFormat.format (double), а затем анализирует предоставленное представление валюты для возврата к исходному значению с помощью NumberFormat.parse (String) .

NumberFormat , а точнее DoubleFormat , «форматировать и анализировать номера для любой локали».

Ссылка: Числовое форматирование Java: DecimalFormat от нашего партнера JCG Дастина Маркса из блога Inspired by Actual Events .