• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GENERATED SOURCE. DO NOT MODIFY. */
2 // © 2017 and later: Unicode, Inc. and others.
3 // License & terms of use: http://www.unicode.org/copyright.html#License
4 package ohos.global.icu.text;
5 
6 import java.io.IOException;
7 import java.io.ObjectInputStream;
8 import java.io.ObjectOutputStream;
9 import java.io.ObjectStreamField;
10 import java.math.BigInteger;
11 import java.math.RoundingMode;
12 import java.text.AttributedCharacterIterator;
13 import java.text.FieldPosition;
14 import java.text.ParsePosition;
15 
16 import ohos.global.icu.impl.FormattedStringBuilder;
17 import ohos.global.icu.impl.FormattedValueStringBuilderImpl;
18 import ohos.global.icu.impl.Utility;
19 import ohos.global.icu.impl.number.AffixUtils;
20 import ohos.global.icu.impl.number.DecimalFormatProperties;
21 import ohos.global.icu.impl.number.DecimalFormatProperties.ParseMode;
22 import ohos.global.icu.impl.number.DecimalQuantity;
23 import ohos.global.icu.impl.number.DecimalQuantity_DualStorageBCD;
24 import ohos.global.icu.impl.number.Padder;
25 import ohos.global.icu.impl.number.Padder.PadPosition;
26 import ohos.global.icu.impl.number.PatternStringParser;
27 import ohos.global.icu.impl.number.PatternStringUtils;
28 import ohos.global.icu.impl.number.parse.NumberParserImpl;
29 import ohos.global.icu.impl.number.parse.ParsedNumber;
30 import ohos.global.icu.lang.UCharacter;
31 import ohos.global.icu.math.BigDecimal;
32 import ohos.global.icu.math.MathContext;
33 import ohos.global.icu.number.FormattedNumber;
34 import ohos.global.icu.number.LocalizedNumberFormatter;
35 import ohos.global.icu.number.NumberFormatter;
36 import ohos.global.icu.text.PluralRules.IFixedDecimal;
37 import ohos.global.icu.util.Currency;
38 import ohos.global.icu.util.Currency.CurrencyUsage;
39 import ohos.global.icu.util.CurrencyAmount;
40 import ohos.global.icu.util.ULocale;
41 import ohos.global.icu.util.ULocale.Category;
42 
43 /**
44  * <strong>[icu enhancement]</strong> ICU's replacement for {@link java.text.DecimalFormat}.&nbsp;Methods, fields, and other functionality specific to ICU are labeled '<strong>[icu]</strong>'.
45  *
46  * <p>
47  * <strong>IMPORTANT:</strong> New users are strongly encouraged to see if
48  * {@link NumberFormatter} fits their use case.  Although not deprecated, this
49  * class, DecimalFormat, is only provided for java.text.DecimalFormat compatibility.
50  * <hr>
51  *
52  * <code>DecimalFormat</code> is the primary
53  * concrete subclass of {@link NumberFormat}. It has a variety of features designed to make it
54  * possible to parse and format numbers in any locale, including support for Western, Arabic, or
55  * Indic digits. It supports different flavors of numbers, including integers ("123"), fixed-point
56  * numbers ("123.4"), scientific notation ("1.23E4"), percentages ("12%"), and currency amounts
57  * ("$123.00", "USD123.00", "123.00 US dollars"). All of these flavors can be easily localized.
58  *
59  * <p>To obtain a number formatter for a specific locale (including the default locale), call one of
60  * NumberFormat's factory methods such as {@link NumberFormat#getInstance}. Do not call
61  * DecimalFormat constructors directly unless you know what you are doing.
62  *
63  * <p>DecimalFormat aims to comply with the specification <a
64  * href="http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns">UTS #35</a>. Read
65  * the specification for more information on how all the properties in DecimalFormat fit together.
66  *
67  * <p><strong>NOTE:</strong> Starting in ICU 60, there is a new set of APIs for localized number
68  * formatting that are designed to be an improvement over DecimalFormat.  New users are discouraged
69  * from using DecimalFormat.  For more information, see the package ohos.global.icu.number.
70  *
71  * <h3>Example Usage</h3>
72  *
73  * <p>Customize settings on a DecimalFormat instance from the NumberFormat factory:
74  *
75  * <blockquote>
76  *
77  * <pre>
78  * NumberFormat f = NumberFormat.getInstance(loc);
79  * if (f instanceof DecimalFormat) {
80  *     ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
81  *     ((DecimalFormat) f).setMinimumGroupingDigits(2);
82  * }
83  * </pre>
84  *
85  * </blockquote>
86  *
87  * <p>Quick and dirty print out a number using the localized number, currency, and percent format
88  * for each locale:
89  *
90  * <blockquote>
91  *
92  * <pre>
93  * for (ULocale uloc : ULocale.getAvailableLocales()) {
94  *     System.out.print(uloc + ":\t");
95  *     System.out.print(NumberFormat.getInstance(uloc).format(1.23));
96  *     System.out.print("\t");
97  *     System.out.print(NumberFormat.getCurrencyInstance(uloc).format(1.23));
98  *     System.out.print("\t");
99  *     System.out.print(NumberFormat.getPercentInstance(uloc).format(1.23));
100  *     System.out.println();
101  * }
102  * </pre>
103  *
104  * </blockquote>
105  *
106  * <h3>Properties and Symbols</h3>
107  *
108  * <p>A DecimalFormat object encapsulates a set of <em>properties</em> and a set of
109  * <em>symbols</em>. Grouping size, rounding mode, and affixes are examples of properties. Locale
110  * digits and the characters used for grouping and decimal separators are examples of symbols.
111  *
112  * <p>To set a custom set of symbols, use {@link #setDecimalFormatSymbols}. Use the various other
113  * setters in this class to set custom values for the properties.
114  *
115  * <h3>Rounding</h3>
116  *
117  * <p>DecimalFormat provides three main strategies to specify the position at which numbers should
118  * be rounded:
119  *
120  * <ol>
121  *   <li><strong>Magnitude:</strong> Display a fixed number of fraction digits; this is the most
122  *       common form.
123  *   <li><strong>Increment:</strong> Round numbers to the closest multiple of a certain increment,
124  *       such as 0.05. This is common in currencies.
125  *   <li><strong>Significant Digits:</strong> Round numbers such that a fixed number of nonzero
126  *       digits are shown. This is most common in scientific notation.
127  * </ol>
128  *
129  * <p>It is not possible to specify more than one rounding strategy. For example, setting a rounding
130  * increment in conjunction with significant digits results in undefined behavior.
131  *
132  * <p>It is also possible to specify the <em>rounding mode</em> to use. The default rounding mode is
133  * "half even", which rounds numbers to their closest increment, with ties broken in favor of
134  * trailing numbers being even. For more information, see {@link #setRoundingMode} and <a
135  * href="http://userguide.icu-project.org/formatparse/numbers/rounding-modes">the ICU User
136  * Guide</a>.
137  *
138  * <h3>Pattern Strings</h3>
139  *
140  * <p>A <em>pattern string</em> is a way to serialize some of the available properties for decimal
141  * formatting. However, not all properties are capable of being serialized into a pattern string;
142  * see {@link #applyPattern} for more information.
143  *
144  * <p>Most users should not need to interface with pattern strings directly.
145  *
146  * <p>ICU DecimalFormat aims to follow the specification for pattern strings in <a
147  * href="http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns">UTS #35</a>.
148  * Refer to that specification for more information on pattern string syntax.
149  *
150  * <h4>Pattern String BNF</h4>
151  *
152  * The following BNF is used when parsing the pattern string into property values:
153  *
154  * <pre>
155  * pattern    := subpattern (';' subpattern)?
156  * subpattern := prefix? number exponent? suffix?
157  * number     := (integer ('.' fraction)?) | sigDigits
158  * prefix     := '&#92;u0000'..'&#92;uFFFD' - specialCharacters
159  * suffix     := '&#92;u0000'..'&#92;uFFFD' - specialCharacters
160  * integer    := '#'* '0'* '0'
161  * fraction   := '0'* '#'*
162  * sigDigits  := '#'* '@' '@'* '#'*
163  * exponent   := 'E' '+'? '0'* '0'
164  * padSpec    := '*' padChar
165  * padChar    := '&#92;u0000'..'&#92;uFFFD' - quote
166  * &#32;
167  * Notation:
168  *   X*       0 or more instances of X
169  *   X?       0 or 1 instances of X
170  *   X|Y      either X or Y
171  *   C..D     any character from C up to D, inclusive
172  *   S-T      characters in S, except those in T
173  * </pre>
174  *
175  * <p>The first subpattern is for positive numbers. The second (optional) subpattern is for negative
176  * numbers.
177  *
178  * <p>Not indicated in the BNF syntax above:
179  *
180  * <ul>
181  *   <li>The grouping separator ',' can occur inside the integer and sigDigits elements, between any
182  *       two pattern characters of that element, as long as the integer or sigDigits element is not
183  *       followed by the exponent element.
184  *   <li>Two grouping intervals are recognized: That between the decimal point and the first
185  *       grouping symbol, and that between the first and second grouping symbols. These intervals
186  *       are identical in most locales, but in some locales they differ. For example, the pattern
187  *       &quot;#,##,###&quot; formats the number 123456789 as &quot;12,34,56,789&quot;.
188  *   <li>The pad specifier <code>padSpec</code> may appear before the prefix, after the prefix,
189  *       before the suffix, after the suffix, or not at all.
190  *   <li>In place of '0', the digits '1' through '9' may be used to indicate a rounding increment.
191  * </ul>
192  *
193  * <h3>Parsing</h3>
194  *
195  * <p>DecimalFormat aims to be able to parse anything that it can output as a formatted string.
196  *
197  * <p>There are two primary parse modes: <em>lenient</em> and <em>strict</em>. Lenient mode should
198  * be used if the goal is to parse user input to a number; strict mode should be used if the goal is
199  * validation. The default is lenient mode. For more information, see {@link #setParseStrict}.
200  *
201  * <p><code>DecimalFormat</code> parses all Unicode characters that represent decimal digits, as
202  * defined by {@link UCharacter#digit}. In addition, <code>DecimalFormat</code> also recognizes as
203  * digits the ten consecutive characters starting with the localized zero digit defined in the
204  * {@link DecimalFormatSymbols} object. During formatting, the {@link DecimalFormatSymbols}-based
205  * digits are output.
206  *
207  * <p>Grouping separators are ignored in lenient mode (default). In strict mode, grouping separators
208  * must match the locale-specified grouping sizes.
209  *
210  * <p>When using {@link #parseCurrency}, all currencies are accepted, not just the currency
211  * currently set in the formatter. In addition, the formatter is able to parse every currency style
212  * format for a particular locale no matter which style the formatter is constructed with. For
213  * example, a formatter instance gotten from NumberFormat.getInstance(ULocale,
214  * NumberFormat.CURRENCYSTYLE) can parse both "USD1.00" and "3.00 US dollars".
215  *
216  * <p>Whitespace characters (lenient mode) and control characters (lenient and strict mode),
217  * collectively called "ignorables", do not need to match in identity or quantity between the
218  * pattern string and the input string. For example, the pattern "# %" matches "35 %" (with a single
219  * space), "35%" (with no space), "35&nbsp;%" (with a non-breaking space), and "35&nbsp; %" (with
220  * multiple spaces). Arbitrary ignorables are also allowed at boundaries between the parts of the
221  * number: prefix, number, exponent separator, and suffix. Ignorable whitespace characters are those
222  * having the Unicode "blank" property for regular expressions, defined in UTS #18 Annex C, which is
223  * "horizontal" whitespace, like spaces and tabs, but not "vertical" whitespace, like line breaks.
224  * Ignorable control characters are those in the Unicode set [:Default_Ignorable_Code_Point:].
225  *
226  * <p>If {@link #parse(String, ParsePosition)} fails to parse a string, it returns <code>null</code>
227  * and leaves the parse position unchanged. The convenience method {@link #parse(String)} indicates
228  * parse failure by throwing a {@link java.text.ParseException}.
229  *
230  * <p>Under the hood, a state table parsing engine is used. To debug a parsing failure during
231  * development, use the following pattern to print details about the state table transitions:
232  *
233  * <pre>
234  * ohos.global.icu.impl.number.Parse.DEBUGGING = true;
235  * df.parse("123.45", ppos);
236  * ohos.global.icu.impl.number.Parse.DEBUGGING = false;
237  * </pre>
238  *
239  * <h3>Thread Safety and Best Practices</h3>
240  *
241  * <p>Starting with ICU 59, instances of DecimalFormat are thread-safe.
242  *
243  * <p>Under the hood, DecimalFormat maintains an immutable formatter object that is rebuilt whenever
244  * any of the property setters are called. It is therefore best practice to call property setters
245  * only during construction and not when formatting numbers online.
246  *
247  * @see java.text.Format
248  * @see NumberFormat
249  */
250 public class DecimalFormat extends NumberFormat {
251 
252   /** New serialization in ICU 59: declare different version from ICU 58. */
253   private static final long serialVersionUID = 864413376551465018L;
254 
255   /**
256    * One non-transient field such that deserialization can determine the version of the class. This
257    * field has existed since the very earliest versions of DecimalFormat.
258    */
259   @SuppressWarnings("unused")
260   private final int serialVersionOnStream = 5;
261 
262   //=====================================================================================//
263   //                                   INSTANCE FIELDS                                   //
264   //=====================================================================================//
265 
266   // Fields are package-private, so that subclasses can use them.
267   // properties should be final, but clone won't work if we make it final.
268   // All fields are transient because custom serialization is used.
269 
270   /**
271    * The property bag corresponding to user-specified settings and settings from the pattern string.
272    * In principle this should be final, but serialize and clone won't work if it is final. Does not
273    * need to be volatile because the reference never changes.
274    */
275   /* final */ transient DecimalFormatProperties properties;
276 
277   /**
278    * The symbols for the current locale. Volatile because threads may read and write at the same
279    * time.
280    */
281   transient volatile DecimalFormatSymbols symbols;
282 
283   /**
284    * The pre-computed formatter object. Setters cause this to be re-computed atomically. The {@link
285    * #format} method uses the formatter directly without needing to synchronize. Volatile because
286    * threads may read and write at the same time.
287    */
288   transient volatile LocalizedNumberFormatter formatter;
289 
290   /**
291    * The effective properties as exported from the formatter object. Volatile because threads may
292    * read and write at the same time.
293    */
294   transient volatile DecimalFormatProperties exportedProperties;
295 
296   transient volatile NumberParserImpl parser;
297   transient volatile NumberParserImpl currencyParser;
298 
299   //=====================================================================================//
300   //                                    CONSTRUCTORS                                     //
301   //=====================================================================================//
302 
303   /**
304    * Creates a DecimalFormat based on the number pattern and symbols for the default locale. This is
305    * a convenient way to obtain a DecimalFormat instance when internationalization is not the main
306    * concern.
307    *
308    * <p>Most users should call the factory methods on NumberFormat, such as {@link
309    * NumberFormat#getNumberInstance}, which return localized formatter objects, instead of the
310    * DecimalFormat constructors.
311    *
312    * @see NumberFormat#getInstance
313    * @see NumberFormat#getNumberInstance
314    * @see NumberFormat#getCurrencyInstance
315    * @see NumberFormat#getPercentInstance
316    * @see Category#FORMAT
317    */
DecimalFormat()318   public DecimalFormat() {
319     // Use the locale's default pattern
320     ULocale def = ULocale.getDefault(ULocale.Category.FORMAT);
321     String pattern = getPattern(def, NumberFormat.NUMBERSTYLE);
322     symbols = getDefaultSymbols();
323     properties = new DecimalFormatProperties();
324     exportedProperties = new DecimalFormatProperties();
325     // Regression: ignore pattern rounding information if the pattern has currency symbols.
326     setPropertiesFromPattern(pattern, PatternStringParser.IGNORE_ROUNDING_IF_CURRENCY);
327     refreshFormatter();
328   }
329 
330   /**
331    * Creates a DecimalFormat based on the given pattern, using symbols for the default locale. This
332    * is a convenient way to obtain a DecimalFormat instance when internationalization is not the
333    * main concern.
334    *
335    * <p>Most users should call the factory methods on NumberFormat, such as {@link
336    * NumberFormat#getNumberInstance}, which return localized formatter objects, instead of the
337    * DecimalFormat constructors.
338    *
339    * @param pattern A pattern string such as "#,##0.00" conforming to <a
340    *     href="http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns">UTS
341    *     #35</a>.
342    * @throws IllegalArgumentException if the given pattern is invalid.
343    * @see NumberFormat#getInstance
344    * @see NumberFormat#getNumberInstance
345    * @see NumberFormat#getCurrencyInstance
346    * @see NumberFormat#getPercentInstance
347    * @see Category#FORMAT
348    */
DecimalFormat(String pattern)349   public DecimalFormat(String pattern) {
350     symbols = getDefaultSymbols();
351     properties = new DecimalFormatProperties();
352     exportedProperties = new DecimalFormatProperties();
353     // Regression: ignore pattern rounding information if the pattern has currency symbols.
354     setPropertiesFromPattern(pattern, PatternStringParser.IGNORE_ROUNDING_IF_CURRENCY);
355     refreshFormatter();
356   }
357 
358   /**
359    * Creates a DecimalFormat based on the given pattern and symbols. Use this constructor if you
360    * want complete control over the behavior of the formatter.
361    *
362    * <p>Most users should call the factory methods on NumberFormat, such as {@link
363    * NumberFormat#getNumberInstance}, which return localized formatter objects, instead of the
364    * DecimalFormat constructors.
365    *
366    * @param pattern A pattern string such as "#,##0.00" conforming to <a
367    *     href="http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns">UTS
368    *     #35</a>.
369    * @param symbols The set of symbols to be used.
370    * @exception IllegalArgumentException if the given pattern is invalid
371    * @see NumberFormat#getInstance
372    * @see NumberFormat#getNumberInstance
373    * @see NumberFormat#getCurrencyInstance
374    * @see NumberFormat#getPercentInstance
375    * @see DecimalFormatSymbols
376    */
DecimalFormat(String pattern, DecimalFormatSymbols symbols)377   public DecimalFormat(String pattern, DecimalFormatSymbols symbols) {
378     this.symbols = (DecimalFormatSymbols) symbols.clone();
379     properties = new DecimalFormatProperties();
380     exportedProperties = new DecimalFormatProperties();
381     // Regression: ignore pattern rounding information if the pattern has currency symbols.
382     setPropertiesFromPattern(pattern, PatternStringParser.IGNORE_ROUNDING_IF_CURRENCY);
383     refreshFormatter();
384   }
385 
386   /**
387    * Creates a DecimalFormat based on the given pattern and symbols, with additional control over
388    * the behavior of currency. The style argument determines whether currency rounding rules should
389    * override the pattern, and the {@link CurrencyPluralInfo} object is used for customizing the
390    * plural forms used for currency long names.
391    *
392    * <p>Most users should call the factory methods on NumberFormat, such as {@link
393    * NumberFormat#getNumberInstance}, which return localized formatter objects, instead of the
394    * DecimalFormat constructors.
395    *
396    * @param pattern a non-localized pattern string
397    * @param symbols the set of symbols to be used
398    * @param infoInput the information used for currency plural format, including currency plural
399    *     patterns and plural rules.
400    * @param style the decimal formatting style, it is one of the following values:
401    *     NumberFormat.NUMBERSTYLE; NumberFormat.CURRENCYSTYLE; NumberFormat.PERCENTSTYLE;
402    *     NumberFormat.SCIENTIFICSTYLE; NumberFormat.INTEGERSTYLE; NumberFormat.ISOCURRENCYSTYLE;
403    *     NumberFormat.PLURALCURRENCYSTYLE;
404    */
DecimalFormat( String pattern, DecimalFormatSymbols symbols, CurrencyPluralInfo infoInput, int style)405   public DecimalFormat(
406       String pattern, DecimalFormatSymbols symbols, CurrencyPluralInfo infoInput, int style) {
407     this(pattern, symbols, style);
408     properties.setCurrencyPluralInfo(infoInput);
409     refreshFormatter();
410   }
411 
412   /** Package-private constructor used by NumberFormat. */
DecimalFormat(String pattern, DecimalFormatSymbols symbols, int choice)413   DecimalFormat(String pattern, DecimalFormatSymbols symbols, int choice) {
414     this.symbols = (DecimalFormatSymbols) symbols.clone();
415     properties = new DecimalFormatProperties();
416     exportedProperties = new DecimalFormatProperties();
417     // If choice is a currency type, ignore the rounding information.
418     if (choice == CURRENCYSTYLE
419         || choice == ISOCURRENCYSTYLE
420         || choice == ACCOUNTINGCURRENCYSTYLE
421         || choice == CASHCURRENCYSTYLE
422         || choice == STANDARDCURRENCYSTYLE
423         || choice == PLURALCURRENCYSTYLE) {
424       setPropertiesFromPattern(pattern, PatternStringParser.IGNORE_ROUNDING_ALWAYS);
425     } else {
426       setPropertiesFromPattern(pattern, PatternStringParser.IGNORE_ROUNDING_IF_CURRENCY);
427     }
428     refreshFormatter();
429   }
430 
getDefaultSymbols()431   private static DecimalFormatSymbols getDefaultSymbols() {
432     return DecimalFormatSymbols.getInstance();
433   }
434 
435   /**
436    * Parses the given pattern string and overwrites the settings specified in the pattern string.
437    * The properties corresponding to the following setters are overwritten, either with their
438    * default values or with the value specified in the pattern string:
439    *
440    * <ol>
441    *   <li>{@link #setDecimalSeparatorAlwaysShown}
442    *   <li>{@link #setExponentSignAlwaysShown}
443    *   <li>{@link #setFormatWidth}
444    *   <li>{@link #setGroupingSize}
445    *   <li>{@link #setMultiplier} (percent/permille)
446    *   <li>{@link #setMaximumFractionDigits}
447    *   <li>{@link #setMaximumIntegerDigits}
448    *   <li>{@link #setMaximumSignificantDigits}
449    *   <li>{@link #setMinimumExponentDigits}
450    *   <li>{@link #setMinimumFractionDigits}
451    *   <li>{@link #setMinimumIntegerDigits}
452    *   <li>{@link #setMinimumSignificantDigits}
453    *   <li>{@link #setPadPosition}
454    *   <li>{@link #setPadCharacter}
455    *   <li>{@link #setRoundingIncrement}
456    *   <li>{@link #setSecondaryGroupingSize}
457    * </ol>
458    *
459    * All other settings remain untouched.
460    *
461    * <p>For more information on pattern strings, see <a
462    * href="http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns">UTS #35</a>.
463    */
applyPattern(String pattern)464   public synchronized void applyPattern(String pattern) {
465     setPropertiesFromPattern(pattern, PatternStringParser.IGNORE_ROUNDING_NEVER);
466     // Backwards compatibility: clear out user-specified prefix and suffix,
467     // as well as CurrencyPluralInfo.
468     properties.setPositivePrefix(null);
469     properties.setNegativePrefix(null);
470     properties.setPositiveSuffix(null);
471     properties.setNegativeSuffix(null);
472     properties.setCurrencyPluralInfo(null);
473     refreshFormatter();
474   }
475 
476   /**
477    * Converts the given string to standard notation and then parses it using {@link #applyPattern}.
478    * This method is provided for backwards compatibility and should not be used in new projects.
479    *
480    * <p>Localized notation means that instead of using generic placeholders in the pattern, you use
481    * the corresponding locale-specific characters instead. For example, in locale <em>fr-FR</em>,
482    * the period in the pattern "0.000" means "decimal" in standard notation (as it does in every
483    * other locale), but it means "grouping" in localized notation.
484    *
485    * @param localizedPattern The pattern string in localized notation.
486    */
applyLocalizedPattern(String localizedPattern)487   public synchronized void applyLocalizedPattern(String localizedPattern) {
488     String pattern = PatternStringUtils.convertLocalized(localizedPattern, symbols, false);
489     applyPattern(pattern);
490   }
491 
492   //=====================================================================================//
493   //                                CLONE AND SERIALIZE                                  //
494   //=====================================================================================//
495 
496   /***/
497   @Override
clone()498   public Object clone() {
499     DecimalFormat other = (DecimalFormat) super.clone();
500     other.symbols = (DecimalFormatSymbols) symbols.clone();
501     other.properties = properties.clone();
502     other.exportedProperties = new DecimalFormatProperties();
503     other.refreshFormatter();
504     return other;
505   }
506 
507   /**
508    * Custom serialization: save property bag and symbols; the formatter object can be re-created
509    * from just that amount of information.
510    */
writeObject(ObjectOutputStream oos)511   private synchronized void writeObject(ObjectOutputStream oos) throws IOException {
512     // ICU 59 custom serialization.
513     // Write class metadata and serialVersionOnStream field:
514     oos.defaultWriteObject();
515     // Extra int for possible future use:
516     oos.writeInt(0);
517     // 1) Property Bag
518     oos.writeObject(properties);
519     // 2) DecimalFormatSymbols
520     oos.writeObject(symbols);
521   }
522 
523   /**
524    * Custom serialization: re-create object from serialized property bag and symbols. Also supports
525    * reading from the legacy (pre-ICU4J 59) format and converting it to the new form.
526    */
readObject(ObjectInputStream ois)527   private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
528     ObjectInputStream.GetField fieldGetter = ois.readFields();
529     ObjectStreamField[] serializedFields = fieldGetter.getObjectStreamClass().getFields();
530     int serialVersion = fieldGetter.get("serialVersionOnStream", -1);
531 
532     if (serialVersion > 5) {
533       throw new IOException(
534           "Cannot deserialize newer ohos.global.icu.text.DecimalFormat (v" + serialVersion + ")");
535     } else if (serialVersion == 5) {
536       ///// ICU 59+ SERIALIZATION FORMAT /////
537       // We expect this field and no other fields:
538       if (serializedFields.length > 1) {
539         throw new IOException("Too many fields when reading serial version 5");
540       }
541       // Extra int for possible future use:
542       ois.readInt();
543       // 1) Property Bag
544       Object serializedProperties = ois.readObject();
545       if (serializedProperties instanceof DecimalFormatProperties) {
546         // ICU 60+
547         properties = (DecimalFormatProperties) serializedProperties;
548       } else {
549         // ICU 59
550         properties = ((ohos.global.icu.impl.number.Properties) serializedProperties).getInstance();
551       }
552       // 2) DecimalFormatSymbols
553       symbols = (DecimalFormatSymbols) ois.readObject();
554       // Re-build transient fields
555       exportedProperties = new DecimalFormatProperties();
556       refreshFormatter();
557     } else {
558       ///// LEGACY SERIALIZATION FORMAT /////
559       properties = new DecimalFormatProperties();
560       // Loop through the fields. Not all fields necessarily exist in the serialization.
561       String pp = null, ppp = null, ps = null, psp = null;
562       String np = null, npp = null, ns = null, nsp = null;
563       for (ObjectStreamField field : serializedFields) {
564         String name = field.getName();
565         if (name.equals("decimalSeparatorAlwaysShown")) {
566           setDecimalSeparatorAlwaysShown(fieldGetter.get("decimalSeparatorAlwaysShown", false));
567         } else if (name.equals("exponentSignAlwaysShown")) {
568           setExponentSignAlwaysShown(fieldGetter.get("exponentSignAlwaysShown", false));
569         } else if (name.equals("formatWidth")) {
570           setFormatWidth(fieldGetter.get("formatWidth", 0));
571         } else if (name.equals("groupingSize")) {
572           setGroupingSize(fieldGetter.get("groupingSize", (byte) 3));
573         } else if (name.equals("groupingSize2")) {
574           setSecondaryGroupingSize(fieldGetter.get("groupingSize2", (byte) 0));
575         } else if (name.equals("maxSignificantDigits")) {
576           setMaximumSignificantDigits(fieldGetter.get("maxSignificantDigits", 6));
577         } else if (name.equals("minExponentDigits")) {
578           setMinimumExponentDigits(fieldGetter.get("minExponentDigits", (byte) 0));
579         } else if (name.equals("minSignificantDigits")) {
580           setMinimumSignificantDigits(fieldGetter.get("minSignificantDigits", 1));
581         } else if (name.equals("multiplier")) {
582           setMultiplier(fieldGetter.get("multiplier", 1));
583         } else if (name.equals("pad")) {
584           setPadCharacter(fieldGetter.get("pad", '\u0020'));
585         } else if (name.equals("padPosition")) {
586           setPadPosition(fieldGetter.get("padPosition", 0));
587         } else if (name.equals("parseBigDecimal")) {
588           setParseBigDecimal(fieldGetter.get("parseBigDecimal", false));
589         } else if (name.equals("parseRequireDecimalPoint")) {
590           setDecimalPatternMatchRequired(fieldGetter.get("parseRequireDecimalPoint", false));
591         } else if (name.equals("roundingMode")) {
592           setRoundingMode(fieldGetter.get("roundingMode", 0));
593         } else if (name.equals("useExponentialNotation")) {
594           setScientificNotation(fieldGetter.get("useExponentialNotation", false));
595         } else if (name.equals("useSignificantDigits")) {
596           setSignificantDigitsUsed(fieldGetter.get("useSignificantDigits", false));
597         } else if (name.equals("currencyPluralInfo")) {
598           setCurrencyPluralInfo((CurrencyPluralInfo) fieldGetter.get("currencyPluralInfo", null));
599         } else if (name.equals("mathContext")) {
600           setMathContextICU((MathContext) fieldGetter.get("mathContext", null));
601         } else if (name.equals("negPrefixPattern")) {
602           npp = (String) fieldGetter.get("negPrefixPattern", null);
603         } else if (name.equals("negSuffixPattern")) {
604           nsp = (String) fieldGetter.get("negSuffixPattern", null);
605         } else if (name.equals("negativePrefix")) {
606           np = (String) fieldGetter.get("negativePrefix", null);
607         } else if (name.equals("negativeSuffix")) {
608           ns = (String) fieldGetter.get("negativeSuffix", null);
609         } else if (name.equals("posPrefixPattern")) {
610           ppp = (String) fieldGetter.get("posPrefixPattern", null);
611         } else if (name.equals("posSuffixPattern")) {
612           psp = (String) fieldGetter.get("posSuffixPattern", null);
613         } else if (name.equals("positivePrefix")) {
614           pp = (String) fieldGetter.get("positivePrefix", null);
615         } else if (name.equals("positiveSuffix")) {
616           ps = (String) fieldGetter.get("positiveSuffix", null);
617         } else if (name.equals("roundingIncrement")) {
618           setRoundingIncrement((java.math.BigDecimal) fieldGetter.get("roundingIncrement", null));
619         } else if (name.equals("symbols")) {
620           setDecimalFormatSymbols((DecimalFormatSymbols) fieldGetter.get("symbols", null));
621         } else {
622           // The following fields are ignored:
623           // "PARSE_MAX_EXPONENT"
624           // "currencySignCount"
625           // "style"
626           // "attributes"
627           // "currencyChoice"
628           // "formatPattern"
629           // "currencyUsage" => ignore this because the old code puts currencyUsage directly into min/max fraction.
630         }
631       }
632       // Resolve affixes
633       if (npp == null) {
634         properties.setNegativePrefix(np);
635       } else {
636         properties.setNegativePrefixPattern(npp);
637       }
638       if (nsp == null) {
639         properties.setNegativeSuffix(ns);
640       } else {
641         properties.setNegativeSuffixPattern(nsp);
642       }
643       if (ppp == null) {
644         properties.setPositivePrefix(pp);
645       } else {
646         properties.setPositivePrefixPattern(ppp);
647       }
648       if (psp == null) {
649         properties.setPositiveSuffix(ps);
650       } else {
651         properties.setPositiveSuffixPattern(psp);
652       }
653       // Extract values from parent NumberFormat class.  Have to use reflection here.
654       java.lang.reflect.Field getter;
655       try {
656         getter = NumberFormat.class.getDeclaredField("groupingUsed");
657         getter.setAccessible(true);
658         setGroupingUsed((Boolean) getter.get(this));
659         getter = NumberFormat.class.getDeclaredField("parseIntegerOnly");
660         getter.setAccessible(true);
661         setParseIntegerOnly((Boolean) getter.get(this));
662         getter = NumberFormat.class.getDeclaredField("maximumIntegerDigits");
663         getter.setAccessible(true);
664         setMaximumIntegerDigits((Integer) getter.get(this));
665         getter = NumberFormat.class.getDeclaredField("minimumIntegerDigits");
666         getter.setAccessible(true);
667         setMinimumIntegerDigits((Integer) getter.get(this));
668         getter = NumberFormat.class.getDeclaredField("maximumFractionDigits");
669         getter.setAccessible(true);
670         setMaximumFractionDigits((Integer) getter.get(this));
671         getter = NumberFormat.class.getDeclaredField("minimumFractionDigits");
672         getter.setAccessible(true);
673         setMinimumFractionDigits((Integer) getter.get(this));
674         getter = NumberFormat.class.getDeclaredField("currency");
675         getter.setAccessible(true);
676         setCurrency((Currency) getter.get(this));
677         getter = NumberFormat.class.getDeclaredField("parseStrict");
678         getter.setAccessible(true);
679         setParseStrict((Boolean) getter.get(this));
680       } catch (IllegalArgumentException e) {
681         throw new IOException(e);
682       } catch (IllegalAccessException e) {
683         throw new IOException(e);
684       } catch (NoSuchFieldException e) {
685         throw new IOException(e);
686       } catch (SecurityException e) {
687         throw new IOException(e);
688       }
689       // Finish initialization
690       if (symbols == null) {
691         symbols = getDefaultSymbols();
692       }
693       exportedProperties = new DecimalFormatProperties();
694       refreshFormatter();
695     }
696   }
697 
698   //=====================================================================================//
699   //                               FORMAT AND PARSE APIS                                 //
700   //=====================================================================================//
701 
702   /**
703    * {@inheritDoc}
704    */
705   @Override
format(double number, StringBuffer result, FieldPosition fieldPosition)706   public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) {
707     DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
708     FormattedStringBuilder string = new FormattedStringBuilder();
709     formatter.formatImpl(dq, string);
710     fieldPositionHelper(dq, string, fieldPosition, result.length());
711     Utility.appendTo(string, result);
712     return result;
713   }
714 
715   /**
716    * {@inheritDoc}
717    */
718   @Override
format(long number, StringBuffer result, FieldPosition fieldPosition)719   public StringBuffer format(long number, StringBuffer result, FieldPosition fieldPosition) {
720     DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
721     FormattedStringBuilder string = new FormattedStringBuilder();
722     formatter.formatImpl(dq, string);
723     fieldPositionHelper(dq, string, fieldPosition, result.length());
724     Utility.appendTo(string, result);
725     return result;
726   }
727 
728   /**
729    * {@inheritDoc}
730    */
731   @Override
format(BigInteger number, StringBuffer result, FieldPosition fieldPosition)732   public StringBuffer format(BigInteger number, StringBuffer result, FieldPosition fieldPosition) {
733     DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
734     FormattedStringBuilder string = new FormattedStringBuilder();
735     formatter.formatImpl(dq, string);
736     fieldPositionHelper(dq, string, fieldPosition, result.length());
737     Utility.appendTo(string, result);
738     return result;
739   }
740 
741   /**
742    * {@inheritDoc}
743    */
744   @Override
format( java.math.BigDecimal number, StringBuffer result, FieldPosition fieldPosition)745   public StringBuffer format(
746       java.math.BigDecimal number, StringBuffer result, FieldPosition fieldPosition) {
747     DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
748     FormattedStringBuilder string = new FormattedStringBuilder();
749     formatter.formatImpl(dq, string);
750     fieldPositionHelper(dq, string, fieldPosition, result.length());
751     Utility.appendTo(string, result);
752     return result;
753   }
754 
755   /**
756    * {@inheritDoc}
757    */
758   @Override
format(BigDecimal number, StringBuffer result, FieldPosition fieldPosition)759   public StringBuffer format(BigDecimal number, StringBuffer result, FieldPosition fieldPosition) {
760     DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
761     FormattedStringBuilder string = new FormattedStringBuilder();
762     formatter.formatImpl(dq, string);
763     fieldPositionHelper(dq, string, fieldPosition, result.length());
764     Utility.appendTo(string, result);
765     return result;
766   }
767 
768   /**
769    * {@inheritDoc}
770    */
771   @Override
formatToCharacterIterator(Object obj)772   public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
773     if (!(obj instanceof Number)) throw new IllegalArgumentException();
774     Number number = (Number) obj;
775     FormattedNumber output = formatter.format(number);
776     return output.toCharacterIterator();
777   }
778 
779   /**
780    * {@inheritDoc}
781    */
782   @Override
format(CurrencyAmount currAmt, StringBuffer result, FieldPosition fieldPosition)783   public StringBuffer format(CurrencyAmount currAmt, StringBuffer result, FieldPosition fieldPosition) {
784     // We need to make localSymbols in order for monetary symbols to be initialized.
785     // Also, bypass the CurrencyAmount override of LocalizedNumberFormatter#format,
786     // because its caching mechanism will not provide any benefit here.
787     DecimalFormatSymbols localSymbols = (DecimalFormatSymbols) symbols.clone();
788     localSymbols.setCurrency(currAmt.getCurrency());
789 
790     DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(currAmt.getNumber());
791     FormattedStringBuilder string = new FormattedStringBuilder();
792     formatter.symbols(localSymbols)
793             .unit(currAmt.getCurrency())
794             .formatImpl(dq, string);
795     fieldPositionHelper(dq, string, fieldPosition, result.length());
796     Utility.appendTo(string, result);
797     return result;
798   }
799 
800   /**
801    * {@inheritDoc}
802    */
803   @Override
parse(String text, ParsePosition parsePosition)804   public Number parse(String text, ParsePosition parsePosition) {
805       if (text == null) {
806           throw new IllegalArgumentException("Text cannot be null");
807       }
808       if (parsePosition == null) {
809           parsePosition = new ParsePosition(0);
810       }
811       if (parsePosition.getIndex() < 0) {
812           throw new IllegalArgumentException("Cannot start parsing at a negative offset");
813       }
814       if (parsePosition.getIndex() >= text.length()) {
815           // For backwards compatibility, this is not an exception, just an empty result.
816           return null;
817       }
818 
819       ParsedNumber result = new ParsedNumber();
820       // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the
821       // parseCurrency method (backwards compatibility)
822       int startIndex = parsePosition.getIndex();
823       NumberParserImpl parser = getParser();
824       parser.parse(text, startIndex, true, result);
825       if (result.success()) {
826           parsePosition.setIndex(result.charEnd);
827           // TODO: Accessing properties here is technically not thread-safe
828           Number number = result.getNumber(parser.getParseFlags());
829           // Backwards compatibility: return ohos.global.icu.math.BigDecimal
830           if (number instanceof java.math.BigDecimal) {
831               number = safeConvertBigDecimal((java.math.BigDecimal) number);
832           }
833           return number;
834       } else {
835           parsePosition.setErrorIndex(startIndex + result.charEnd);
836           return null;
837       }
838   }
839 
840   /**
841    * {@inheritDoc}
842    */
843   @Override
parseCurrency(CharSequence text, ParsePosition parsePosition)844   public CurrencyAmount parseCurrency(CharSequence text, ParsePosition parsePosition) {
845       if (text == null) {
846           throw new IllegalArgumentException("Text cannot be null");
847       }
848       if (parsePosition == null) {
849           parsePosition = new ParsePosition(0);
850       }
851       if (parsePosition.getIndex() < 0) {
852           throw new IllegalArgumentException("Cannot start parsing at a negative offset");
853       }
854       if (parsePosition.getIndex() >= text.length()) {
855           // For backwards compatibility, this is not an exception, just an empty result.
856           return null;
857       }
858 
859       ParsedNumber result = new ParsedNumber();
860       int startIndex = parsePosition.getIndex();
861       NumberParserImpl parser = getCurrencyParser();
862       parser.parse(text.toString(), startIndex, true, result);
863       if (result.success()) {
864           parsePosition.setIndex(result.charEnd);
865           // TODO: Accessing properties here is technically not thread-safe
866           Number number = result.getNumber(parser.getParseFlags());
867           // Backwards compatibility: return ohos.global.icu.math.BigDecimal
868           if (number instanceof java.math.BigDecimal) {
869               number = safeConvertBigDecimal((java.math.BigDecimal) number);
870           }
871           Currency currency = Currency.getInstance(result.currencyCode);
872           return new CurrencyAmount(number, currency);
873       } else {
874           parsePosition.setErrorIndex(startIndex + result.charEnd);
875           return null;
876       }
877   }
878 
879   //=====================================================================================//
880   //                                GETTERS AND SETTERS                                  //
881   //=====================================================================================//
882 
883   /**
884    * Returns a copy of the decimal format symbols used by this formatter.
885    *
886    * @return desired DecimalFormatSymbols
887    * @see DecimalFormatSymbols
888    */
getDecimalFormatSymbols()889   public synchronized DecimalFormatSymbols getDecimalFormatSymbols() {
890     return (DecimalFormatSymbols) symbols.clone();
891   }
892 
893   /**
894    * Sets the decimal format symbols used by this formatter. The formatter uses a copy of the
895    * provided symbols.
896    *
897    * @param newSymbols desired DecimalFormatSymbols
898    * @see DecimalFormatSymbols
899    */
setDecimalFormatSymbols(DecimalFormatSymbols newSymbols)900   public synchronized void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
901     symbols = (DecimalFormatSymbols) newSymbols.clone();
902     refreshFormatter();
903   }
904 
905   /**
906    * <strong>Affixes:</strong> Gets the positive prefix string currently being used to format
907    * numbers.
908    *
909    * <p>If the affix was specified via the pattern, the string returned by this method will have
910    * locale symbols substituted in place of special characters according to the LDML specification.
911    * If the affix was specified via {@link #setPositivePrefix}, the string will be returned
912    * literally.
913    *
914    * @return The string being prepended to positive numbers.
915    */
getPositivePrefix()916   public synchronized String getPositivePrefix() {
917     return formatter.getAffixImpl(true, false);
918   }
919 
920   /**
921    * <strong>Affixes:</strong> Sets the string to prepend to positive numbers. For example, if you
922    * set the value "#", then the number 123 will be formatted as "#123" in the locale
923    * <em>en-US</em>.
924    *
925    * <p>Using this method overrides the affix specified via the pattern, and unlike the pattern, the
926    * string given to this method will be interpreted literally WITHOUT locale symbol substitutions.
927    *
928    * @param prefix The literal string to prepend to positive numbers.
929    */
setPositivePrefix(String prefix)930   public synchronized void setPositivePrefix(String prefix) {
931     if (prefix == null) {
932       throw new NullPointerException();
933     }
934     properties.setPositivePrefix(prefix);
935     refreshFormatter();
936   }
937 
938   /**
939    * <strong>Affixes:</strong> Gets the negative prefix string currently being used to format
940    * numbers.
941    *
942    * <p>If the affix was specified via the pattern, the string returned by this method will have
943    * locale symbols substituted in place of special characters according to the LDML specification.
944    * If the affix was specified via {@link #setNegativePrefix}, the string will be returned
945    * literally.
946    *
947    * @return The string being prepended to negative numbers.
948    */
getNegativePrefix()949   public synchronized String getNegativePrefix() {
950     return formatter.getAffixImpl(true, true);
951   }
952 
953   /**
954    * <strong>Affixes:</strong> Sets the string to prepend to negative numbers. For example, if you
955    * set the value "#", then the number -123 will be formatted as "#123" in the locale
956    * <em>en-US</em> (overriding the implicit default '-' in the pattern).
957    *
958    * <p>Using this method overrides the affix specified via the pattern, and unlike the pattern, the
959    * string given to this method will be interpreted literally WITHOUT locale symbol substitutions.
960    *
961    * @param prefix The literal string to prepend to negative numbers.
962    */
setNegativePrefix(String prefix)963   public synchronized void setNegativePrefix(String prefix) {
964     if (prefix == null) {
965       throw new NullPointerException();
966     }
967     properties.setNegativePrefix(prefix);
968     refreshFormatter();
969   }
970 
971   /**
972    * <strong>Affixes:</strong> Gets the positive suffix string currently being used to format
973    * numbers.
974    *
975    * <p>If the affix was specified via the pattern, the string returned by this method will have
976    * locale symbols substituted in place of special characters according to the LDML specification.
977    * If the affix was specified via {@link #setPositiveSuffix}, the string will be returned
978    * literally.
979    *
980    * @return The string being appended to positive numbers.
981    */
getPositiveSuffix()982   public synchronized String getPositiveSuffix() {
983     return formatter.getAffixImpl(false, false);
984   }
985 
986   /**
987    * <strong>Affixes:</strong> Sets the string to append to positive numbers. For example, if you
988    * set the value "#", then the number 123 will be formatted as "123#" in the locale
989    * <em>en-US</em>.
990    *
991    * <p>Using this method overrides the affix specified via the pattern, and unlike the pattern, the
992    * string given to this method will be interpreted literally WITHOUT locale symbol substitutions.
993    *
994    * @param suffix The literal string to append to positive numbers.
995    */
setPositiveSuffix(String suffix)996   public synchronized void setPositiveSuffix(String suffix) {
997     if (suffix == null) {
998       throw new NullPointerException();
999     }
1000     properties.setPositiveSuffix(suffix);
1001     refreshFormatter();
1002   }
1003 
1004   /**
1005    * <strong>Affixes:</strong> Gets the negative suffix string currently being used to format
1006    * numbers.
1007    *
1008    * <p>If the affix was specified via the pattern, the string returned by this method will have
1009    * locale symbols substituted in place of special characters according to the LDML specification.
1010    * If the affix was specified via {@link #setNegativeSuffix}, the string will be returned
1011    * literally.
1012    *
1013    * @return The string being appended to negative numbers.
1014    */
getNegativeSuffix()1015   public synchronized String getNegativeSuffix() {
1016     return formatter.getAffixImpl(false, true);
1017   }
1018 
1019   /**
1020    * <strong>Affixes:</strong> Sets the string to append to negative numbers. For example, if you
1021    * set the value "#", then the number 123 will be formatted as "123#" in the locale
1022    * <em>en-US</em>.
1023    *
1024    * <p>Using this method overrides the affix specified via the pattern, and unlike the pattern, the
1025    * string given to this method will be interpreted literally WITHOUT locale symbol substitutions.
1026    *
1027    * @param suffix The literal string to append to negative numbers.
1028    */
setNegativeSuffix(String suffix)1029   public synchronized void setNegativeSuffix(String suffix) {
1030     if (suffix == null) {
1031       throw new NullPointerException();
1032     }
1033     properties.setNegativeSuffix(suffix);
1034     refreshFormatter();
1035   }
1036 
1037   /**
1038    * <strong>[icu]</strong> Returns whether the sign is being shown on positive numbers.
1039    *
1040    * @return Whether the sign is shown on positive numbers and zero.
1041    * @see #setSignAlwaysShown
1042    */
isSignAlwaysShown()1043   public synchronized boolean isSignAlwaysShown() {
1044     // This is not in the exported properties
1045     return properties.getSignAlwaysShown();
1046   }
1047 
1048   /**
1049    * Sets whether to always shown the plus sign ('+' in <em>en</em>) on positive numbers. The rules
1050    * in UTS #35 section 3.2.1 will be followed to ensure a locale-aware placement of the sign.
1051    *
1052    * <p>More specifically, the following strategy will be used to place the plus sign:
1053    *
1054    * <ol>
1055    *   <li><em>Patterns without a negative subpattern:</em> The locale's plus sign will be prepended
1056    *       to the positive prefix.
1057    *   <li><em>Patterns with a negative subpattern without a '-' sign (e.g., accounting):</em> The
1058    *       locale's plus sign will be prepended to the positive prefix, as in case 1.
1059    *   <li><em>Patterns with a negative subpattern that has a '-' sign:</em> The locale's plus sign
1060    *       will substitute the '-' in the negative subpattern. The positive subpattern will be
1061    *       unused.
1062    * </ol>
1063    *
1064    * This method is designed to be used <em>instead of</em> applying a pattern containing an
1065    * explicit plus sign, such as "+0;-0". The behavior when combining this method with explicit plus
1066    * signs in the pattern is undefined.
1067    *
1068    * @param value true to always show a sign; false to hide the sign on positive numbers and zero.
1069    */
setSignAlwaysShown(boolean value)1070   public synchronized void setSignAlwaysShown(boolean value) {
1071     properties.setSignAlwaysShown(value);
1072     refreshFormatter();
1073   }
1074 
1075   /**
1076    * Returns the multiplier being applied to numbers before they are formatted.
1077    *
1078    * @see #setMultiplier
1079    */
getMultiplier()1080   public synchronized int getMultiplier() {
1081     if (properties.getMultiplier() != null) {
1082       return properties.getMultiplier().intValue();
1083     } else {
1084       return (int) Math.pow(10, properties.getMagnitudeMultiplier());
1085     }
1086   }
1087 
1088   /**
1089    * Sets a number that will be used to multiply all numbers prior to formatting. For example, when
1090    * formatting percents, a multiplier of 100 can be used.
1091    *
1092    * <p>If a percent or permille sign is specified in the pattern, the multiplier is automatically
1093    * set to 100 or 1000, respectively.
1094    *
1095    * <p>If the number specified here is a power of 10, a more efficient code path will be used.
1096    *
1097    * @param multiplier The number by which all numbers passed to {@link #format} will be multiplied.
1098    * @throws IllegalArgumentException If the given multiplier is zero.
1099    * @throws ArithmeticException when inverting multiplier produces a non-terminating decimal result
1100    *         in conjunction with MathContext of unlimited precision.
1101    */
setMultiplier(int multiplier)1102   public synchronized void setMultiplier(int multiplier) {
1103     if (multiplier == 0) {
1104       throw new IllegalArgumentException("Multiplier must be nonzero.");
1105     }
1106 
1107     // Try to convert to a magnitude multiplier first
1108     int delta = 0;
1109     int value = multiplier;
1110     while (value != 1) {
1111       delta++;
1112       int temp = value / 10;
1113       if (temp * 10 != value) {
1114         delta = -1;
1115         break;
1116       }
1117       value = temp;
1118     }
1119     if (delta != -1) {
1120       properties.setMagnitudeMultiplier(delta);
1121       properties.setMultiplier(null);
1122     } else {
1123       properties.setMagnitudeMultiplier(0);
1124       properties.setMultiplier(java.math.BigDecimal.valueOf(multiplier));
1125     }
1126     refreshFormatter();
1127   }
1128 
1129   /**
1130    * <strong>[icu]</strong> Returns the increment to which numbers are being rounded.
1131    *
1132    * @see #setRoundingIncrement
1133    */
getRoundingIncrement()1134   public synchronized java.math.BigDecimal getRoundingIncrement() {
1135     return exportedProperties.getRoundingIncrement();
1136   }
1137 
1138   /**
1139    * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Sets an increment, or interval, to which
1140    * numbers are rounded. For example, a rounding increment of 0.05 will cause the number 1.23 to be
1141    * rounded to 1.25 in the default rounding mode.
1142    *
1143    * <p>The rounding increment can be specified via the pattern string: for example, the pattern
1144    * "#,##0.05" encodes a rounding increment of 0.05.
1145    *
1146    * <p>The rounding increment is applied <em>after</em> any multipliers might take effect; for
1147    * example, in scientific notation or when {@link #setMultiplier} is used.
1148    *
1149    * <p>See {@link #setMaximumFractionDigits} and {@link #setMaximumSignificantDigits} for two other
1150    * ways of specifying rounding strategies.
1151    *
1152    * @param increment The increment to which numbers are to be rounded.
1153    * @see #setRoundingMode
1154    * @see #setMaximumFractionDigits
1155    * @see #setMaximumSignificantDigits
1156    */
setRoundingIncrement(java.math.BigDecimal increment)1157   public synchronized void setRoundingIncrement(java.math.BigDecimal increment) {
1158     // Backwards compatibility: ignore rounding increment if zero,
1159     // and instead set maximum fraction digits.
1160     if (increment != null && increment.compareTo(java.math.BigDecimal.ZERO) == 0) {
1161       properties.setMaximumFractionDigits(Integer.MAX_VALUE);
1162       return;
1163     }
1164 
1165     properties.setRoundingIncrement(increment);
1166     refreshFormatter();
1167   }
1168 
1169   /**
1170    * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Overload of {@link
1171    * #setRoundingIncrement(java.math.BigDecimal)}.
1172    *
1173    * @param increment The increment to which numbers are to be rounded.
1174    * @see #setRoundingIncrement
1175    */
setRoundingIncrement(BigDecimal increment)1176   public synchronized void setRoundingIncrement(BigDecimal increment) {
1177     java.math.BigDecimal javaBigDecimal = (increment == null) ? null : increment.toBigDecimal();
1178     setRoundingIncrement(javaBigDecimal);
1179   }
1180 
1181   /**
1182    * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Overload of {@link
1183    * #setRoundingIncrement(java.math.BigDecimal)}.
1184    *
1185    * @param increment The increment to which numbers are to be rounded.
1186    * @see #setRoundingIncrement
1187    */
setRoundingIncrement(double increment)1188   public synchronized void setRoundingIncrement(double increment) {
1189     if (increment == 0) {
1190       setRoundingIncrement((java.math.BigDecimal) null);
1191     } else {
1192       java.math.BigDecimal javaBigDecimal = java.math.BigDecimal.valueOf(increment);
1193       setRoundingIncrement(javaBigDecimal);
1194     }
1195   }
1196 
1197   /**
1198    * Returns the rounding mode being used to round numbers.
1199    *
1200    * @see #setRoundingMode
1201    */
1202   @Override
getRoundingMode()1203   public synchronized int getRoundingMode() {
1204     RoundingMode mode = exportedProperties.getRoundingMode();
1205     return (mode == null) ? 0 : mode.ordinal();
1206   }
1207 
1208   /**
1209    * <strong>Rounding and Digit Limits:</strong> Sets the {@link RoundingMode} used to round
1210    * numbers. The default rounding mode is HALF_EVEN, which rounds decimals to their closest whole
1211    * number, and rounds to the closest even number if at the midpoint.
1212    *
1213    * <p>For more detail on rounding modes, see <a
1214    * href="http://userguide.icu-project.org/formatparse/numbers/rounding-modes">the ICU User
1215    * Guide</a>.
1216    *
1217    * <p>For backwards compatibility, the rounding mode is specified as an int argument, which can be
1218    * from either the constants in {@link BigDecimal} or the ordinal value of {@link RoundingMode}.
1219    * The following two calls are functionally equivalent.
1220    *
1221    * <pre>
1222    * df.setRoundingMode(BigDecimal.ROUND_CEILING);
1223    * df.setRoundingMode(RoundingMode.CEILING.ordinal());
1224    * </pre>
1225    *
1226    * @param roundingMode The integer constant rounding mode to use when formatting numbers.
1227    */
1228   @Override
setRoundingMode(int roundingMode)1229   public synchronized void setRoundingMode(int roundingMode) {
1230     properties.setRoundingMode(RoundingMode.valueOf(roundingMode));
1231     refreshFormatter();
1232   }
1233 
1234   /**
1235    * <strong>[icu]</strong> Returns the {@link java.math.MathContext} being used to round numbers.
1236    *
1237    * @see #setMathContext
1238    */
getMathContext()1239   public synchronized java.math.MathContext getMathContext() {
1240     java.math.MathContext mathContext = exportedProperties.getMathContext();
1241     assert mathContext != null;
1242     return mathContext;
1243   }
1244 
1245   /**
1246    * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Sets the {@link java.math.MathContext} used
1247    * to round numbers. A "math context" encodes both a rounding mode and a number of significant
1248    * digits. Most users should call {@link #setRoundingMode} and/or {@link
1249    * #setMaximumSignificantDigits} instead of this method.
1250    *
1251    * <p>When formatting, since no division is ever performed, the default MathContext is unlimited
1252    * significant digits. However, when division occurs during parsing to correct for percentages and
1253    * multipliers, a MathContext of 34 digits, the IEEE 754R Decimal128 standard, is used by default.
1254    * If you require more than 34 digits when parsing, you can set a custom MathContext using this
1255    * method.
1256    *
1257    * @param mathContext The MathContext to use when rounding numbers.
1258    * @throws ArithmeticException when inverting multiplier produces a non-terminating decimal result
1259    *         in conjunction with MathContext of unlimited precision.
1260    * @see java.math.MathContext
1261    */
setMathContext(java.math.MathContext mathContext)1262   public synchronized void setMathContext(java.math.MathContext mathContext) {
1263     properties.setMathContext(mathContext);
1264     refreshFormatter();
1265   }
1266 
1267   // Remember the ICU math context form in order to be able to return it from the API.
1268   // NOTE: This value is not serialized. (should it be?)
1269   private transient int icuMathContextForm = MathContext.PLAIN;
1270 
1271   /**
1272    * <strong>[icu]</strong> Returns the {@link ohos.global.icu.math.MathContext} being used to round numbers.
1273    *
1274    * @see #setMathContext
1275    */
getMathContextICU()1276   public synchronized MathContext getMathContextICU() {
1277     java.math.MathContext mathContext = getMathContext();
1278     return new MathContext(
1279         mathContext.getPrecision(),
1280         icuMathContextForm,
1281         false,
1282         mathContext.getRoundingMode().ordinal());
1283   }
1284 
1285   /**
1286    * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Overload of {@link #setMathContext} for
1287    * {@link ohos.global.icu.math.MathContext}.
1288    *
1289    * @param mathContextICU The MathContext to use when rounding numbers.
1290    * @throws ArithmeticException when inverting multiplier produces a non-terminating decimal result
1291    *         in conjunction with MathContext of unlimited precision.
1292    * @see #setMathContext(java.math.MathContext)
1293    */
setMathContextICU(MathContext mathContextICU)1294   public synchronized void setMathContextICU(MathContext mathContextICU) {
1295     icuMathContextForm = mathContextICU.getForm();
1296     java.math.MathContext mathContext;
1297     if (mathContextICU.getLostDigits()) {
1298       // The getLostDigits() feature in ICU MathContext means "throw an ArithmeticException if
1299       // rounding causes digits to be lost". That feature is called RoundingMode.UNNECESSARY in
1300       // Java MathContext.
1301       mathContext = new java.math.MathContext(mathContextICU.getDigits(), RoundingMode.UNNECESSARY);
1302     } else {
1303       mathContext =
1304           new java.math.MathContext(
1305               mathContextICU.getDigits(), RoundingMode.valueOf(mathContextICU.getRoundingMode()));
1306     }
1307     setMathContext(mathContext);
1308   }
1309 
1310   /**
1311    * Returns the effective minimum number of digits before the decimal separator.
1312    *
1313    * @see #setMinimumIntegerDigits
1314    */
1315   @Override
getMinimumIntegerDigits()1316   public synchronized int getMinimumIntegerDigits() {
1317     return exportedProperties.getMinimumIntegerDigits();
1318   }
1319 
1320   /**
1321    * <strong>Rounding and Digit Limits:</strong> Sets the minimum number of digits to display before
1322    * the decimal separator. If the number has fewer than this many digits, the number is padded with
1323    * zeros.
1324    *
1325    * <p>For example, if minimum integer digits is 3, the number 12.3 will be printed as "001.23".
1326    *
1327    * <p>Minimum integer and minimum and maximum fraction digits can be specified via the pattern
1328    * string. For example, "#,#00.00#" has 2 minimum integer digits, 2 minimum fraction digits, and 3
1329    * maximum fraction digits. Note that it is not possible to specify maximium integer digits in the
1330    * pattern except in scientific notation.
1331    *
1332    * <p>If minimum and maximum integer, fraction, or significant digits conflict with each other,
1333    * the most recently specified value is used. For example, if there is a formatter with minInt=5,
1334    * and then you set maxInt=3, then minInt will be changed to 3.
1335    *
1336    * @param value The minimum number of digits before the decimal separator.
1337    */
1338   @Override
setMinimumIntegerDigits(int value)1339   public synchronized void setMinimumIntegerDigits(int value) {
1340     // For backwards compatibility, conflicting min/max need to keep the most recent setting.
1341     int max = properties.getMaximumIntegerDigits();
1342     if (max >= 0 && max < value) {
1343       properties.setMaximumIntegerDigits(value);
1344     }
1345     properties.setMinimumIntegerDigits(value);
1346     refreshFormatter();
1347   }
1348 
1349   /**
1350    * Returns the effective maximum number of digits before the decimal separator.
1351    *
1352    * @see #setMaximumIntegerDigits
1353    */
1354   @Override
getMaximumIntegerDigits()1355   public synchronized int getMaximumIntegerDigits() {
1356     return exportedProperties.getMaximumIntegerDigits();
1357   }
1358 
1359   /**
1360    * <strong>Rounding and Digit Limits:</strong> Sets the maximum number of digits to display before
1361    * the decimal separator. If the number has more than this many digits, the number is truncated.
1362    *
1363    * <p>For example, if maximum integer digits is 3, the number 12345 will be printed as "345".
1364    *
1365    * <p>Minimum integer and minimum and maximum fraction digits can be specified via the pattern
1366    * string. For example, "#,#00.00#" has 2 minimum integer digits, 2 minimum fraction digits, and 3
1367    * maximum fraction digits. Note that it is not possible to specify maximium integer digits in the
1368    * pattern except in scientific notation.
1369    *
1370    * <p>If minimum and maximum integer, fraction, or significant digits conflict with each other,
1371    * the most recently specified value is used. For example, if there is a formatter with minInt=5,
1372    * and then you set maxInt=3, then minInt will be changed to 3.
1373    *
1374    * @param value The maximum number of digits before the decimal separator.
1375    */
1376   @Override
setMaximumIntegerDigits(int value)1377   public synchronized void setMaximumIntegerDigits(int value) {
1378     int min = properties.getMinimumIntegerDigits();
1379     if (min >= 0 && min > value) {
1380       properties.setMinimumIntegerDigits(value);
1381     }
1382     properties.setMaximumIntegerDigits(value);
1383     refreshFormatter();
1384   }
1385 
1386   /**
1387    * Returns the effective minimum number of integer digits after the decimal separator.
1388    *
1389    * @see #setMaximumIntegerDigits
1390    */
1391   @Override
getMinimumFractionDigits()1392   public synchronized int getMinimumFractionDigits() {
1393     return exportedProperties.getMinimumFractionDigits();
1394   }
1395 
1396   /**
1397    * <strong>Rounding and Digit Limits:</strong> Sets the minimum number of digits to display after
1398    * the decimal separator. If the number has fewer than this many digits, the number is padded with
1399    * zeros.
1400    *
1401    * <p>For example, if minimum fraction digits is 2, the number 123.4 will be printed as "123.40".
1402    *
1403    * <p>Minimum integer and minimum and maximum fraction digits can be specified via the pattern
1404    * string. For example, "#,#00.00#" has 2 minimum integer digits, 2 minimum fraction digits, and 3
1405    * maximum fraction digits. Note that it is not possible to specify maximium integer digits in the
1406    * pattern except in scientific notation.
1407    *
1408    * <p>If minimum and maximum integer, fraction, or significant digits conflict with each other,
1409    * the most recently specified value is used. For example, if there is a formatter with minInt=5,
1410    * and then you set maxInt=3, then minInt will be changed to 3.
1411    *
1412    * <p>See {@link #setRoundingIncrement} and {@link #setMaximumSignificantDigits} for two other
1413    * ways of specifying rounding strategies.
1414    *
1415    * @param value The minimum number of integer digits after the decimal separator.
1416    * @see #setRoundingMode
1417    * @see #setRoundingIncrement
1418    * @see #setMaximumSignificantDigits
1419    */
1420   @Override
setMinimumFractionDigits(int value)1421   public synchronized void setMinimumFractionDigits(int value) {
1422     int max = properties.getMaximumFractionDigits();
1423     if (max >= 0 && max < value) {
1424       properties.setMaximumFractionDigits(value);
1425     }
1426     properties.setMinimumFractionDigits(value);
1427     refreshFormatter();
1428   }
1429 
1430   /**
1431    * Returns the effective maximum number of integer digits after the decimal separator.
1432    *
1433    * @see #setMaximumIntegerDigits
1434    */
1435   @Override
getMaximumFractionDigits()1436   public synchronized int getMaximumFractionDigits() {
1437     return exportedProperties.getMaximumFractionDigits();
1438   }
1439 
1440   /**
1441    * <strong>Rounding and Digit Limits:</strong> Sets the maximum number of digits to display after
1442    * the decimal separator. If the number has more than this many digits, the number is rounded
1443    * according to the rounding mode.
1444    *
1445    * <p>For example, if maximum fraction digits is 2, the number 123.456 will be printed as
1446    * "123.46".
1447    *
1448    * <p>Minimum integer and minimum and maximum fraction digits can be specified via the pattern
1449    * string. For example, "#,#00.00#" has 2 minimum integer digits, 2 minimum fraction digits, and 3
1450    * maximum fraction digits. Note that it is not possible to specify maximium integer digits in the
1451    * pattern except in scientific notation.
1452    *
1453    * <p>If minimum and maximum integer, fraction, or significant digits conflict with each other,
1454    * the most recently specified value is used. For example, if there is a formatter with minInt=5,
1455    * and then you set maxInt=3, then minInt will be changed to 3.
1456    *
1457    * @param value The maximum number of integer digits after the decimal separator.
1458    * @see #setRoundingMode
1459    */
1460   @Override
setMaximumFractionDigits(int value)1461   public synchronized void setMaximumFractionDigits(int value) {
1462     int min = properties.getMinimumFractionDigits();
1463     if (min >= 0 && min > value) {
1464       properties.setMinimumFractionDigits(value);
1465     }
1466     properties.setMaximumFractionDigits(value);
1467     refreshFormatter();
1468   }
1469 
1470   /**
1471    * <strong>[icu]</strong> Returns whether significant digits are being used in rounding.
1472    *
1473    * @see #setSignificantDigitsUsed
1474    */
areSignificantDigitsUsed()1475   public synchronized boolean areSignificantDigitsUsed() {
1476     return properties.getMinimumSignificantDigits() != -1
1477         || properties.getMaximumSignificantDigits() != -1;
1478   }
1479 
1480   /**
1481    * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Sets whether significant digits are to be
1482    * used in rounding.
1483    *
1484    * <p>Calling <code>df.setSignificantDigitsUsed(true)</code> is functionally equivalent to:
1485    *
1486    * <pre>
1487    * df.setMinimumSignificantDigits(1);
1488    * df.setMaximumSignificantDigits(6);
1489    * </pre>
1490    *
1491    * @param useSignificantDigits true to enable significant digit rounding; false to disable it.
1492    */
setSignificantDigitsUsed(boolean useSignificantDigits)1493   public synchronized void setSignificantDigitsUsed(boolean useSignificantDigits) {
1494     int oldMinSig = properties.getMinimumSignificantDigits();
1495     int oldMaxSig = properties.getMaximumSignificantDigits();
1496     // These are the default values from the old implementation.
1497     if (useSignificantDigits) {
1498       if (oldMinSig != -1 || oldMaxSig != -1) {
1499         return;
1500       }
1501     } else {
1502       if (oldMinSig == -1 && oldMaxSig == -1) {
1503         return;
1504       }
1505     }
1506     int minSig = useSignificantDigits ? 1 : -1;
1507     int maxSig = useSignificantDigits ? 6 : -1;
1508     properties.setMinimumSignificantDigits(minSig);
1509     properties.setMaximumSignificantDigits(maxSig);
1510     refreshFormatter();
1511   }
1512 
1513   /**
1514    * <strong>[icu]</strong> Returns the effective minimum number of significant digits displayed.
1515    *
1516    * @see #setMinimumSignificantDigits
1517    */
getMinimumSignificantDigits()1518   public synchronized int getMinimumSignificantDigits() {
1519     return exportedProperties.getMinimumSignificantDigits();
1520   }
1521 
1522   /**
1523    * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Sets the minimum number of significant
1524    * digits to be displayed. If the number of significant digits is less than this value, the number
1525    * will be padded with zeros as necessary.
1526    *
1527    * <p>For example, if minimum significant digits is 3 and the number is 1.2, the number will be
1528    * printed as "1.20".
1529    *
1530    * <p>If minimum and maximum integer, fraction, or significant digits conflict with each other,
1531    * the most recently specified value is used. For example, if there is a formatter with minInt=5,
1532    * and then you set maxInt=3, then minInt will be changed to 3.
1533    *
1534    * @param value The minimum number of significant digits to display.
1535    */
setMinimumSignificantDigits(int value)1536   public synchronized void setMinimumSignificantDigits(int value) {
1537     int max = properties.getMaximumSignificantDigits();
1538     if (max >= 0 && max < value) {
1539       properties.setMaximumSignificantDigits(value);
1540     }
1541     properties.setMinimumSignificantDigits(value);
1542     refreshFormatter();
1543   }
1544 
1545   /**
1546    * <strong>[icu]</strong> Returns the effective maximum number of significant digits displayed.
1547    *
1548    * @see #setMaximumSignificantDigits
1549    */
getMaximumSignificantDigits()1550   public synchronized int getMaximumSignificantDigits() {
1551     return exportedProperties.getMaximumSignificantDigits();
1552   }
1553 
1554   /**
1555    * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Sets the maximum number of significant
1556    * digits to be displayed. If the number of significant digits in the number exceeds this value,
1557    * the number will be rounded according to the current rounding mode.
1558    *
1559    * <p>For example, if maximum significant digits is 3 and the number is 12345, the number will be
1560    * printed as "12300".
1561    *
1562    * <p>If minimum and maximum integer, fraction, or significant digits conflict with each other,
1563    * the most recently specified value is used. For example, if there is a formatter with minInt=5,
1564    * and then you set maxInt=3, then minInt will be changed to 3.
1565    *
1566    * <p>See {@link #setRoundingIncrement} and {@link #setMaximumFractionDigits} for two other ways
1567    * of specifying rounding strategies.
1568    *
1569    * @param value The maximum number of significant digits to display.
1570    * @see #setRoundingMode
1571    * @see #setRoundingIncrement
1572    * @see #setMaximumFractionDigits
1573    */
setMaximumSignificantDigits(int value)1574   public synchronized void setMaximumSignificantDigits(int value) {
1575     int min = properties.getMinimumSignificantDigits();
1576     if (min >= 0 && min > value) {
1577       properties.setMinimumSignificantDigits(value);
1578     }
1579     properties.setMaximumSignificantDigits(value);
1580     refreshFormatter();
1581   }
1582 
1583   /**
1584    * Returns the minimum number of characters in formatted output.
1585    *
1586    * @see #setFormatWidth
1587    */
getFormatWidth()1588   public synchronized int getFormatWidth() {
1589     return properties.getFormatWidth();
1590   }
1591 
1592   /**
1593    * <strong>Padding:</strong> Sets the minimum width of the string output by the formatting
1594    * pipeline. For example, if padding is enabled and paddingWidth is set to 6, formatting the
1595    * number "3.14159" with the pattern "0.00" will result in "··3.14" if '·' is your padding string.
1596    *
1597    * <p>If the number is longer than your padding width, the number will display as if no padding
1598    * width had been specified, which may result in strings longer than the padding width.
1599    *
1600    * <p>Padding can be specified in the pattern string using the '*' symbol. For example, the format
1601    * "*x######0" has a format width of 7 and a pad character of 'x'.
1602    *
1603    * <p>Padding is currently counted in UTF-16 code units; see <a
1604    * href="http://bugs.icu-project.org/trac/ticket/13034">ticket #13034</a> for more information.
1605    *
1606    * @param width The minimum number of characters in the output.
1607    * @see #setPadCharacter
1608    * @see #setPadPosition
1609    */
setFormatWidth(int width)1610   public synchronized void setFormatWidth(int width) {
1611     properties.setFormatWidth(width);
1612     refreshFormatter();
1613   }
1614 
1615   /**
1616    * <strong>[icu]</strong> Returns the character used for padding.
1617    *
1618    * @see #setPadCharacter
1619    */
getPadCharacter()1620   public synchronized char getPadCharacter() {
1621     CharSequence paddingString = properties.getPadString();
1622     if (paddingString == null) {
1623       return Padder.FALLBACK_PADDING_STRING.charAt(0);
1624     } else {
1625       return paddingString.charAt(0);
1626     }
1627   }
1628 
1629   /**
1630    * <strong>[icu]</strong> <strong>Padding:</strong> Sets the character used to pad numbers that are narrower than
1631    * the width specified in {@link #setFormatWidth}.
1632    *
1633    * <p>In the pattern string, the padding character is the token that follows '*' before or after
1634    * the prefix or suffix.
1635    *
1636    * @param padChar The character used for padding.
1637    * @see #setFormatWidth
1638    */
setPadCharacter(char padChar)1639   public synchronized void setPadCharacter(char padChar) {
1640     properties.setPadString(Character.toString(padChar));
1641     refreshFormatter();
1642   }
1643 
1644   /**
1645    * <strong>[icu]</strong> Returns the position used for padding.
1646    *
1647    * @see #setPadPosition
1648    */
getPadPosition()1649   public synchronized int getPadPosition() {
1650     PadPosition loc = properties.getPadPosition();
1651     return (loc == null) ? PAD_BEFORE_PREFIX : loc.toOld();
1652   }
1653 
1654   /**
1655    * <strong>[icu]</strong> <strong>Padding:</strong> Sets the position where to insert the pad character when
1656    * narrower than the width specified in {@link #setFormatWidth}. For example, consider the pattern
1657    * "P123S" with padding width 8 and padding char "*". The four positions are:
1658    *
1659    * <ul>
1660    *   <li>{@link DecimalFormat#PAD_BEFORE_PREFIX} ⇒ "***P123S"
1661    *   <li>{@link DecimalFormat#PAD_AFTER_PREFIX} ⇒ "P***123S"
1662    *   <li>{@link DecimalFormat#PAD_BEFORE_SUFFIX} ⇒ "P123***S"
1663    *   <li>{@link DecimalFormat#PAD_AFTER_SUFFIX} ⇒ "P123S***"
1664    * </ul>
1665    *
1666    * @param padPos The position used for padding.
1667    * @see #setFormatWidth
1668    */
setPadPosition(int padPos)1669   public synchronized void setPadPosition(int padPos) {
1670     properties.setPadPosition(PadPosition.fromOld(padPos));
1671     refreshFormatter();
1672   }
1673 
1674   /**
1675    * <strong>[icu]</strong> Returns whether scientific (exponential) notation is enabled on this formatter.
1676    *
1677    * @see #setScientificNotation
1678    */
isScientificNotation()1679   public synchronized boolean isScientificNotation() {
1680     return properties.getMinimumExponentDigits() != -1;
1681   }
1682 
1683   /**
1684    * <strong>[icu]</strong> <strong>Scientific Notation:</strong> Sets whether this formatter should print in
1685    * scientific (exponential) notation. For example, if scientific notation is enabled, the number
1686    * 123000 will be printed as "1.23E5" in locale <em>en-US</em>. A locale-specific symbol is used
1687    * as the exponent separator.
1688    *
1689    * <p>Calling <code>df.setScientificNotation(true)</code> is functionally equivalent to calling
1690    * <code>df.setMinimumExponentDigits(1)</code>.
1691    *
1692    * @param useScientific true to enable scientific notation; false to disable it.
1693    * @see #setMinimumExponentDigits
1694    */
setScientificNotation(boolean useScientific)1695   public synchronized void setScientificNotation(boolean useScientific) {
1696     if (useScientific) {
1697       properties.setMinimumExponentDigits(1);
1698     } else {
1699       properties.setMinimumExponentDigits(-1);
1700     }
1701     refreshFormatter();
1702   }
1703 
1704   /**
1705    * <strong>[icu]</strong> Returns the minimum number of digits printed in the exponent in scientific notation.
1706    *
1707    * @see #setMinimumExponentDigits
1708    */
getMinimumExponentDigits()1709   public synchronized byte getMinimumExponentDigits() {
1710     return (byte) properties.getMinimumExponentDigits();
1711   }
1712 
1713   /**
1714    * <strong>[icu]</strong> <strong>Scientific Notation:</strong> Sets the minimum number of digits to be printed in
1715    * the exponent. For example, if minimum exponent digits is 3, the number 123000 will be printed
1716    * as "1.23E005".
1717    *
1718    * <p>This setting corresponds to the number of zeros after the 'E' in a pattern string such as
1719    * "0.00E000".
1720    *
1721    * @param minExpDig The minimum number of digits in the exponent.
1722    */
setMinimumExponentDigits(byte minExpDig)1723   public synchronized void setMinimumExponentDigits(byte minExpDig) {
1724     properties.setMinimumExponentDigits(minExpDig);
1725     refreshFormatter();
1726   }
1727 
1728   /**
1729    * <strong>[icu]</strong> Returns whether the sign (plus or minus) is always printed in scientific notation.
1730    *
1731    * @see #setExponentSignAlwaysShown
1732    */
isExponentSignAlwaysShown()1733   public synchronized boolean isExponentSignAlwaysShown() {
1734     return properties.getExponentSignAlwaysShown();
1735   }
1736 
1737   /**
1738    * <strong>[icu]</strong> <strong>Scientific Notation:</strong> Sets whether the sign (plus or minus) is always to
1739    * be shown in the exponent in scientific notation. For example, if this setting is enabled, the
1740    * number 123000 will be printed as "1.23E+5" in locale <em>en-US</em>. The number 0.0000123 will
1741    * always be printed as "1.23E-5" in locale <em>en-US</em> whether or not this setting is enabled.
1742    *
1743    * <p>This setting corresponds to the '+' in a pattern such as "0.00E+0".
1744    *
1745    * @param expSignAlways true to always shown the sign in the exponent; false to show it for
1746    *     negatives but not positives.
1747    */
setExponentSignAlwaysShown(boolean expSignAlways)1748   public synchronized void setExponentSignAlwaysShown(boolean expSignAlways) {
1749     properties.setExponentSignAlwaysShown(expSignAlways);
1750     refreshFormatter();
1751   }
1752 
1753   /**
1754    * Returns whether or not grouping separators are being printed in the output.
1755    *
1756    * @see #setGroupingUsed
1757    */
1758   @Override
isGroupingUsed()1759   public synchronized boolean isGroupingUsed() {
1760     return properties.getGroupingUsed();
1761   }
1762 
1763   /**
1764    * <strong>Grouping:</strong> Sets whether grouping is to be used when formatting numbers.
1765    * Grouping means whether the thousands, millions, billions, and larger powers of ten should be
1766    * separated by a grouping separator (a comma in <em>en-US</em>).
1767    *
1768    * <p>For example, if grouping is enabled, 12345 will be printed as "12,345" in <em>en-US</em>. If
1769    * grouping were disabled, it would instead be printed as simply "12345".
1770    *
1771    * @param enabled true to enable grouping separators; false to disable them.
1772    * @see #setGroupingSize
1773    * @see #setSecondaryGroupingSize
1774    */
1775   @Override
setGroupingUsed(boolean enabled)1776   public synchronized void setGroupingUsed(boolean enabled) {
1777     properties.setGroupingUsed(enabled);
1778     refreshFormatter();
1779   }
1780 
1781   /**
1782    * Returns the primary grouping size in use.
1783    *
1784    * @see #setGroupingSize
1785    */
getGroupingSize()1786   public synchronized int getGroupingSize() {
1787     if (properties.getGroupingSize() < 0) {
1788       return 0;
1789     }
1790     return properties.getGroupingSize();
1791   }
1792 
1793   /**
1794    * <strong>Grouping:</strong> Sets the primary grouping size (distance between grouping
1795    * separators) used when formatting large numbers. For most locales, this defaults to 3: the
1796    * number of digits between the ones and thousands place, between thousands and millions, and so
1797    * forth.
1798    *
1799    * <p>For example, with a grouping size of 3, the number 1234567 will be formatted as "1,234,567".
1800    *
1801    * <p>Grouping size can also be specified in the pattern: for example, "#,##0" corresponds to a
1802    * grouping size of 3.
1803    *
1804    * @param width The grouping size to use.
1805    * @see #setSecondaryGroupingSize
1806    */
setGroupingSize(int width)1807   public synchronized void setGroupingSize(int width) {
1808     properties.setGroupingSize(width);
1809     refreshFormatter();
1810   }
1811 
1812   /**
1813    * <strong>[icu]</strong> Returns the secondary grouping size in use.
1814    *
1815    * @see #setSecondaryGroupingSize
1816    */
getSecondaryGroupingSize()1817   public synchronized int getSecondaryGroupingSize() {
1818     int grouping2 = properties.getSecondaryGroupingSize();
1819     if (grouping2 < 0) {
1820       return 0;
1821     }
1822     return grouping2;
1823   }
1824 
1825   /**
1826    * <strong>[icu]</strong> <strong>Grouping:</strong> Sets the secondary grouping size (distance between grouping
1827    * separators after the first separator) used when formatting large numbers. In many south Asian
1828    * locales, this is set to 2.
1829    *
1830    * <p>For example, with primary grouping size 3 and secondary grouping size 2, the number 1234567
1831    * will be formatted as "12,34,567".
1832    *
1833    * <p>Grouping size can also be specified in the pattern: for example, "#,##,##0" corresponds to a
1834    * primary grouping size of 3 and a secondary grouping size of 2.
1835    *
1836    * @param width The secondary grouping size to use.
1837    * @see #setGroupingSize
1838    */
setSecondaryGroupingSize(int width)1839   public synchronized void setSecondaryGroupingSize(int width) {
1840     properties.setSecondaryGroupingSize(width);
1841     refreshFormatter();
1842   }
1843 
1844   /**
1845    * <strong>[icu]</strong> Returns the minimum number of digits before grouping is triggered.
1846    *
1847    * @see #setMinimumGroupingDigits
1848    */
getMinimumGroupingDigits()1849   public synchronized int getMinimumGroupingDigits() {
1850     if (properties.getMinimumGroupingDigits() > 0) {
1851       return properties.getMinimumGroupingDigits();
1852     }
1853     return 1;
1854   }
1855 
1856   /**
1857    * <strong>[icu]</strong> Sets the minimum number of digits that must be before the first grouping separator in
1858    * order for the grouping separator to be printed. For example, if minimum grouping digits is set
1859    * to 2, in <em>en-US</em>, 1234 will be printed as "1234" and 12345 will be printed as "12,345".
1860    *
1861    * @param number The minimum number of digits before grouping is triggered.
1862    */
setMinimumGroupingDigits(int number)1863   public synchronized void setMinimumGroupingDigits(int number) {
1864     properties.setMinimumGroupingDigits(number);
1865     refreshFormatter();
1866   }
1867 
1868   /**
1869    * Returns whether the decimal separator is shown on integers.
1870    *
1871    * @see #setDecimalSeparatorAlwaysShown
1872    */
isDecimalSeparatorAlwaysShown()1873   public synchronized boolean isDecimalSeparatorAlwaysShown() {
1874     return properties.getDecimalSeparatorAlwaysShown();
1875   }
1876 
1877   /**
1878    * <strong>Separators:</strong> Sets whether the decimal separator (a period in <em>en-US</em>) is
1879    * shown on integers. For example, if this setting is turned on, formatting 123 will result in
1880    * "123." with the decimal separator.
1881    *
1882    * <p>This setting can be specified in the pattern for integer formats: "#,##0." is an example.
1883    *
1884    * @param value true to always show the decimal separator; false to show it only when there is a
1885    *     fraction part of the number.
1886    */
setDecimalSeparatorAlwaysShown(boolean value)1887   public synchronized void setDecimalSeparatorAlwaysShown(boolean value) {
1888     properties.setDecimalSeparatorAlwaysShown(value);
1889     refreshFormatter();
1890   }
1891 
1892   /**
1893    * Returns the currency used to display currency amounts. May be null.
1894    *
1895    * @see #setCurrency
1896    * @see DecimalFormatSymbols#getCurrency
1897    */
1898   @Override
getCurrency()1899   public synchronized Currency getCurrency() {
1900     return exportedProperties.getCurrency();
1901   }
1902 
1903   /**
1904    * Sets the currency to be used when formatting numbers. The effect is twofold:
1905    *
1906    * <ol>
1907    *   <li>Substitutions for currency symbols in the pattern string will use this currency
1908    *   <li>The rounding mode will obey the rules for this currency (see {@link #setCurrencyUsage})
1909    * </ol>
1910    *
1911    * <strong>Important:</strong> Displaying the currency in the output requires that the patter
1912    * associated with this formatter contains a currency symbol '¤'. This will be the case if the
1913    * instance was created via {@link #getCurrencyInstance} or one of its friends.
1914    *
1915    * @param currency The currency to use.
1916    */
1917   @Override
setCurrency(Currency currency)1918   public synchronized void setCurrency(Currency currency) {
1919     properties.setCurrency(currency);
1920     if (currency != null) {
1921       symbols.setCurrency(currency);
1922     }
1923     refreshFormatter();
1924   }
1925 
1926   /**
1927    * <strong>[icu]</strong> Returns the strategy for rounding currency amounts.
1928    *
1929    * @see #setCurrencyUsage
1930    */
getCurrencyUsage()1931   public synchronized CurrencyUsage getCurrencyUsage() {
1932     // CurrencyUsage is not exported, so we have to get it from the input property bag.
1933     // TODO: Should we export CurrencyUsage instead?
1934     CurrencyUsage usage = properties.getCurrencyUsage();
1935     if (usage == null) {
1936       usage = CurrencyUsage.STANDARD;
1937     }
1938     return usage;
1939   }
1940 
1941   /**
1942    * <strong>[icu]</strong> Sets the currency-dependent strategy to use when rounding numbers. There are two
1943    * strategies:
1944    *
1945    * <ul>
1946    *   <li>STANDARD: When the amount displayed is intended for banking statements or electronic
1947    *       transfer.
1948    *   <li>CASH: When the amount displayed is intended to be representable in physical currency,
1949    *       like at a cash register.
1950    * </ul>
1951    *
1952    * CASH mode is relevant in currencies that do not have tender down to the penny. For more
1953    * information on the two rounding strategies, see <a
1954    * href="http://unicode.org/reports/tr35/tr35-numbers.html#Supplemental_Currency_Data">UTS
1955    * #35</a>. If omitted, the strategy defaults to STANDARD. To override currency rounding
1956    * altogether, use {@link #setMinimumFractionDigits} and {@link #setMaximumFractionDigits} or
1957    * {@link #setRoundingIncrement}.
1958    *
1959    * @param usage The strategy to use when rounding in the current currency.
1960    */
setCurrencyUsage(CurrencyUsage usage)1961   public synchronized void setCurrencyUsage(CurrencyUsage usage) {
1962     properties.setCurrencyUsage(usage);
1963     refreshFormatter();
1964   }
1965 
1966   /**
1967    * <strong>[icu]</strong> Returns the current instance of CurrencyPluralInfo.
1968    *
1969    * @see #setCurrencyPluralInfo
1970    */
getCurrencyPluralInfo()1971   public synchronized CurrencyPluralInfo getCurrencyPluralInfo() {
1972     // CurrencyPluralInfo also is not exported.
1973     return properties.getCurrencyPluralInfo();
1974   }
1975 
1976   /**
1977    * <strong>[icu]</strong> Sets a custom instance of CurrencyPluralInfo. CurrencyPluralInfo generates pattern
1978    * strings for printing currency long names.
1979    *
1980    * <p><strong>Most users should not call this method directly.</strong> You should instead create
1981    * your formatter via <code>NumberFormat.getInstance(NumberFormat.PLURALCURRENCYSTYLE)</code>.
1982    *
1983    * @param newInfo The CurrencyPluralInfo to use when printing currency long names.
1984    */
setCurrencyPluralInfo(CurrencyPluralInfo newInfo)1985   public synchronized void setCurrencyPluralInfo(CurrencyPluralInfo newInfo) {
1986     properties.setCurrencyPluralInfo(newInfo);
1987     refreshFormatter();
1988   }
1989 
1990   /**
1991    * Returns whether {@link #parse} will always return a BigDecimal.
1992    *
1993    * @see #setParseBigDecimal
1994    */
isParseBigDecimal()1995   public synchronized boolean isParseBigDecimal() {
1996     return properties.getParseToBigDecimal();
1997   }
1998 
1999   /**
2000    * Whether to make {@link #parse} prefer returning a {@link ohos.global.icu.math.BigDecimal} when
2001    * possible. For strings corresponding to return values of Infinity, -Infinity, NaN, and -0.0, a
2002    * Double will be returned even if ParseBigDecimal is enabled.
2003    *
2004    * @param value true to cause {@link #parse} to prefer BigDecimal; false to let {@link #parse}
2005    *     return additional data types like Long or BigInteger.
2006    */
setParseBigDecimal(boolean value)2007   public synchronized void setParseBigDecimal(boolean value) {
2008     properties.setParseToBigDecimal(value);
2009     refreshFormatter();
2010   }
2011 
2012   /**
2013    * Always returns 1000, the default prior to ICU 59.
2014    *
2015    * @deprecated Setting max parse digits has no effect since ICU4J 59.
2016    */
2017   @Deprecated
getParseMaxDigits()2018   public int getParseMaxDigits() {
2019     return 1000;
2020   }
2021 
2022   /**
2023    * @param maxDigits Prior to ICU 59, the maximum number of digits in the output number after
2024    *     exponential notation is applied.
2025    * @deprecated Setting max parse digits has no effect since ICU4J 59.
2026    */
2027   @Deprecated
setParseMaxDigits(int maxDigits)2028   public void setParseMaxDigits(int maxDigits) {}
2029 
2030   /**
2031    * {@inheritDoc}
2032    */
2033   @Override
isParseStrict()2034   public synchronized boolean isParseStrict() {
2035     return properties.getParseMode() == ParseMode.STRICT;
2036   }
2037 
2038   /**
2039    * {@inheritDoc}
2040    */
2041   @Override
setParseStrict(boolean parseStrict)2042   public synchronized void setParseStrict(boolean parseStrict) {
2043     ParseMode mode = parseStrict ? ParseMode.STRICT : ParseMode.LENIENT;
2044     properties.setParseMode(mode);
2045     refreshFormatter();
2046   }
2047 
2048   /**
2049    * Android libcore uses this internal method to set {@link ParseMode#JAVA_COMPATIBILITY}.
2050    * @deprecated This API is ICU internal only.
2051  * @hide draft / provisional / internal are hidden on OHOS
2052    */
2053   @Deprecated
setParseStrictMode(ParseMode parseMode)2054 public synchronized void setParseStrictMode(ParseMode parseMode) {
2055     properties.setParseMode(parseMode);
2056     refreshFormatter();
2057   }
2058 
2059   /**
2060    * {@inheritDoc}
2061    *
2062    * @see #setParseIntegerOnly
2063    */
2064   @Override
isParseIntegerOnly()2065   public synchronized boolean isParseIntegerOnly() {
2066     return properties.getParseIntegerOnly();
2067   }
2068 
2069   /**
2070    * <strong>Parsing:</strong> {@inheritDoc}
2071    *
2072    * <p>This is functionally equivalent to calling {@link #setDecimalPatternMatchRequired} and a
2073    * pattern without a decimal point.
2074    *
2075    * @param parseIntegerOnly true to ignore fractional parts of numbers when parsing; false to
2076    *     consume fractional parts.
2077    */
2078   @Override
setParseIntegerOnly(boolean parseIntegerOnly)2079   public synchronized void setParseIntegerOnly(boolean parseIntegerOnly) {
2080     properties.setParseIntegerOnly(parseIntegerOnly);
2081     refreshFormatter();
2082   }
2083 
2084   /**
2085    * <strong>[icu]</strong> Returns whether the presence of a decimal point must match the pattern.
2086    *
2087    * @see #setDecimalPatternMatchRequired
2088    */
isDecimalPatternMatchRequired()2089   public synchronized boolean isDecimalPatternMatchRequired() {
2090     return properties.getDecimalPatternMatchRequired();
2091   }
2092 
2093   /**
2094    * <strong>[icu]</strong> <strong>Parsing:</strong> This method is used to either <em>require</em> or
2095    * <em>forbid</em> the presence of a decimal point in the string being parsed (disabled by
2096    * default). This feature was designed to be an extra layer of strictness on top of strict
2097    * parsing, although it can be used in either lenient mode or strict mode.
2098    *
2099    * <p>To <em>require</em> a decimal point, call this method in combination with either a pattern
2100    * containing a decimal point or with {@link #setDecimalSeparatorAlwaysShown}.
2101    *
2102    * <pre>
2103    * // Require a decimal point in the string being parsed:
2104    * df.applyPattern("#.");
2105    * df.setDecimalPatternMatchRequired(true);
2106    *
2107    * // Alternatively:
2108    * df.setDecimalSeparatorAlwaysShown(true);
2109    * df.setDecimalPatternMatchRequired(true);
2110    * </pre>
2111    *
2112    * To <em>forbid</em> a decimal point, call this method in combination with a pattern containing
2113    * no decimal point. Alternatively, use {@link #setParseIntegerOnly} for the same behavior without
2114    * depending on the contents of the pattern string.
2115    *
2116    * <pre>
2117    * // Forbid a decimal point in the string being parsed:
2118    * df.applyPattern("#");
2119    * df.setDecimalPatternMatchRequired(true);
2120    * </pre>
2121    *
2122    * @param value true to either require or forbid the decimal point according to the pattern; false
2123    *     to disable this feature.
2124    * @see #setParseIntegerOnly
2125    */
setDecimalPatternMatchRequired(boolean value)2126   public synchronized void setDecimalPatternMatchRequired(boolean value) {
2127     properties.setDecimalPatternMatchRequired(value);
2128     refreshFormatter();
2129   }
2130 
2131   /**
2132    * <strong>[icu]</strong> Returns whether to ignore exponents when parsing.
2133    *
2134    * @see #setParseNoExponent
2135    */
isParseNoExponent()2136   public synchronized boolean isParseNoExponent() {
2137     return properties.getParseNoExponent();
2138   }
2139 
2140   /**
2141    * <strong>[icu]</strong> Specifies whether to stop parsing when an exponent separator is encountered. For
2142    * example, parses "123E4" to 123 (with parse position 3) instead of 1230000 (with parse position
2143    * 5).
2144    *
2145    * @param value true to prevent exponents from being parsed; false to allow them to be parsed.
2146    */
setParseNoExponent(boolean value)2147   public synchronized void setParseNoExponent(boolean value) {
2148     properties.setParseNoExponent(value);
2149     refreshFormatter();
2150   }
2151 
2152   /**
2153    * <strong>[icu]</strong> Returns whether to force case (uppercase/lowercase) to match when parsing.
2154    *
2155    * @see #setParseNoExponent
2156    */
isParseCaseSensitive()2157   public synchronized boolean isParseCaseSensitive() {
2158     return properties.getParseCaseSensitive();
2159   }
2160 
2161   /**
2162    * <strong>[icu]</strong> Specifies whether parsing should require cases to match in affixes, exponent separators,
2163    * and currency codes. Case mapping is performed for each code point using {@link
2164    * UCharacter#foldCase}.
2165    *
2166    * @param value true to force case (uppercase/lowercase) to match when parsing; false to ignore
2167    *     case and perform case folding.
2168    */
setParseCaseSensitive(boolean value)2169   public synchronized void setParseCaseSensitive(boolean value) {
2170     properties.setParseCaseSensitive(value);
2171     refreshFormatter();
2172   }
2173 
2174   // TODO(sffc): Uncomment for ICU 60 API proposal.
2175   //
2176   //  /**
2177   //   * {@icu} Returns the strategy used for choosing between grouping and decimal separators when
2178   //   * parsing.
2179   //   *
2180   //   * @see #setParseGroupingMode
2181   //   * @category Parsing
2182   //   */
2183   //  public synchronized GroupingMode getParseGroupingMode() {
2184   //    return properties.getParseGroupingMode();
2185   //  }
2186   //
2187   //  /**
2188   //   * {@icu} Sets the strategy used during parsing when a code point needs to be interpreted as
2189   //   * either a decimal separator or a grouping separator.
2190   //   *
2191   //   * <p>The comma, period, space, and apostrophe have different meanings in different locales. For
2192   //   * example, in <em>en-US</em> and most American locales, the period is used as a decimal
2193   //   * separator, but in <em>es-PY</em> and most European locales, it is used as a grouping separator.
2194   //   *
2195   //   * Suppose you are in <em>fr-FR</em> the parser encounters the string "1.234".  In <em>fr-FR</em>,
2196   //   * the grouping is a space and the decimal is a comma.  The <em>grouping mode</em> is a mechanism
2197   //   * to let you specify whether to accept the string as 1234 (GroupingMode.DEFAULT) or whether to reject it since the separators
2198   //   * don't match (GroupingMode.RESTRICTED).
2199   //   *
2200   //   * When resolving grouping separators, it is the <em>equivalence class</em> of separators that is considered.
2201   //   * For example, a period is seen as equal to a fixed set of other period-like characters.
2202   //   *
2203   //   * @param groupingMode The strategy to use; either DEFAULT or RESTRICTED.
2204   //   * @category Parsing
2205   //   */
2206   //  public synchronized void setParseGroupingMode(GroupingMode groupingMode) {
2207   //    properties.setParseGroupingMode(groupingMode);
2208   //    refreshFormatter();
2209   //  }
2210 
2211   //=====================================================================================//
2212   //                                     UTILITIES                                       //
2213   //=====================================================================================//
2214 
2215   /**
2216    * Tests for equality between this formatter and another formatter.
2217    *
2218    * <p>If two DecimalFormat instances are equal, then they will always produce the same output.
2219    * However, the reverse is not necessarily true: if two DecimalFormat instances always produce the
2220    * same output, they are not necessarily equal.
2221    */
2222   @Override
equals(Object obj)2223   public synchronized boolean equals(Object obj) {
2224     if (obj == null) return false;
2225     if (obj == this) return true;
2226     if (!(obj instanceof DecimalFormat)) return false;
2227     DecimalFormat other = (DecimalFormat) obj;
2228     return properties.equals(other.properties) && symbols.equals(other.symbols);
2229   }
2230 
2231   /**
2232    * {@inheritDoc}
2233    */
2234   @Override
hashCode()2235   public synchronized int hashCode() {
2236     return properties.hashCode() ^ symbols.hashCode();
2237   }
2238 
2239   /**
2240    * Returns the default value of toString() with extra DecimalFormat-specific information appended
2241    * to the end of the string. This extra information is intended for debugging purposes, and the
2242    * format is not guaranteed to be stable.
2243    */
2244   @Override
toString()2245   public String toString() {
2246     StringBuilder result = new StringBuilder();
2247     result.append(getClass().getName());
2248     result.append("@");
2249     result.append(Integer.toHexString(hashCode()));
2250     result.append(" { symbols@");
2251     result.append(Integer.toHexString(symbols.hashCode()));
2252     synchronized (this) {
2253       properties.toStringBare(result);
2254     }
2255     result.append(" }");
2256     return result.toString();
2257   }
2258 
2259   /**
2260    * Serializes this formatter object to a decimal format pattern string. The result of this method
2261    * is guaranteed to be <em>functionally</em> equivalent to the pattern string used to create this
2262    * instance after incorporating values from the setter methods.
2263    *
2264    * <p>For more information on decimal format pattern strings, see <a
2265    * href="http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns">UTS #35</a>.
2266    *
2267    * <p><strong>Important:</strong> Not all properties are capable of being encoded in a pattern
2268    * string. See a list of properties in {@link #applyPattern}.
2269    *
2270    * @return A decimal format pattern string.
2271    */
toPattern()2272   public synchronized String toPattern() {
2273     // Pull some properties from exportedProperties and others from properties
2274     // to keep affix patterns intact.  In particular, pull rounding properties
2275     // so that CurrencyUsage is reflected properly.
2276     // TODO: Consider putting this logic in PatternString.java instead.
2277     DecimalFormatProperties tprops = new DecimalFormatProperties().copyFrom(properties);
2278     boolean useCurrency = ((tprops.getCurrency() != null)
2279             || tprops.getCurrencyPluralInfo() != null
2280             || tprops.getCurrencyUsage() != null
2281             || AffixUtils.hasCurrencySymbols(tprops.getPositivePrefixPattern())
2282             || AffixUtils.hasCurrencySymbols(tprops.getPositiveSuffixPattern())
2283             || AffixUtils.hasCurrencySymbols(tprops.getNegativePrefixPattern())
2284             || AffixUtils.hasCurrencySymbols(tprops.getNegativeSuffixPattern()));
2285     if (useCurrency) {
2286       tprops.setMinimumFractionDigits(exportedProperties.getMinimumFractionDigits());
2287       tprops.setMaximumFractionDigits(exportedProperties.getMaximumFractionDigits());
2288       tprops.setRoundingIncrement(exportedProperties.getRoundingIncrement());
2289     }
2290     return PatternStringUtils.propertiesToPatternString(tprops);
2291   }
2292 
2293   /**
2294    * Calls {@link #toPattern} and converts the string to localized notation. For more information on
2295    * localized notation, see {@link #applyLocalizedPattern}. This method is provided for backwards
2296    * compatibility and should not be used in new projects.
2297    *
2298    * @return A decimal format pattern string in localized notation.
2299    */
toLocalizedPattern()2300   public synchronized String toLocalizedPattern() {
2301     String pattern = toPattern();
2302     return PatternStringUtils.convertLocalized(pattern, symbols, true);
2303   }
2304 
2305   /**
2306    * Converts this DecimalFormat to a NumberFormatter.  Starting in ICU 60,
2307    * NumberFormatter is the recommended way to format numbers.
2308    *
2309    * @return An instance of {@link LocalizedNumberFormatter} with the same behavior as this instance of
2310    * DecimalFormat.
2311    * @see NumberFormatter
2312    */
toNumberFormatter()2313   public LocalizedNumberFormatter toNumberFormatter() {
2314       return formatter;
2315   }
2316 
2317   /**
2318    * @deprecated This API is ICU internal only.
2319  * @hide draft / provisional / internal are hidden on OHOS
2320    */
2321   @Deprecated
getFixedDecimal(double number)2322   public IFixedDecimal getFixedDecimal(double number) {
2323     return formatter.format(number).getFixedDecimal();
2324   }
2325 
2326   /** Rebuilds the formatter object from the property bag. */
refreshFormatter()2327   void refreshFormatter() {
2328     if (exportedProperties == null) {
2329       // exportedProperties is null only when the formatter is not ready yet.
2330       // The only time when this happens is during legacy deserialization.
2331       return;
2332     }
2333     ULocale locale = this.getLocale(ULocale.ACTUAL_LOCALE);
2334     if (locale == null) {
2335       // Constructor
2336       locale = symbols.getLocale(ULocale.ACTUAL_LOCALE);
2337     }
2338     if (locale == null) {
2339       // Deserialization
2340       locale = symbols.getULocale();
2341     }
2342     assert locale != null;
2343     formatter = NumberFormatter.fromDecimalFormat(properties, symbols, exportedProperties).locale(locale);
2344 
2345     // Lazy-initialize the parsers only when we need them.
2346     parser = null;
2347     currencyParser = null;
2348   }
2349 
getParser()2350   NumberParserImpl getParser() {
2351     if (parser == null) {
2352       parser = NumberParserImpl.createParserFromProperties(properties, symbols, false);
2353     }
2354     return parser;
2355   }
2356 
getCurrencyParser()2357   NumberParserImpl getCurrencyParser() {
2358     if (currencyParser == null) {
2359       currencyParser = NumberParserImpl.createParserFromProperties(properties, symbols, true);
2360     }
2361     return currencyParser;
2362   }
2363 
2364   /**
2365    * Converts a java.math.BigDecimal to a ohos.global.icu.math.BigDecimal with fallback for numbers
2366    * outside of the range supported by ohos.global.icu.math.BigDecimal.
2367    *
2368    * @param number
2369    * @return
2370    */
safeConvertBigDecimal(java.math.BigDecimal number)2371   private Number safeConvertBigDecimal(java.math.BigDecimal number) {
2372     try {
2373       return new ohos.global.icu.math.BigDecimal(number);
2374     } catch (NumberFormatException e) {
2375       if (number.signum() > 0 && number.scale() < 0) {
2376         return Double.POSITIVE_INFINITY;
2377       } else if (number.scale() < 0) {
2378         return Double.NEGATIVE_INFINITY;
2379       } else if (number.signum() < 0) {
2380         return -0.0;
2381       } else {
2382         return 0.0;
2383       }
2384     }
2385   }
2386 
2387   /**
2388    * Updates the property bag with settings from the given pattern.
2389    *
2390    * @param pattern The pattern string to parse.
2391    * @param ignoreRounding Whether to leave out rounding information (minFrac, maxFrac, and rounding
2392    *     increment) when parsing the pattern. This may be desirable if a custom rounding mode, such
2393    *     as CurrencyUsage, is to be used instead. One of {@link
2394    *     PatternStringParser#IGNORE_ROUNDING_ALWAYS}, {@link PatternStringParser#IGNORE_ROUNDING_IF_CURRENCY},
2395    *     or {@link PatternStringParser#IGNORE_ROUNDING_NEVER}.
2396    * @see PatternAndPropertyUtils#parseToExistingProperties
2397    */
setPropertiesFromPattern(String pattern, int ignoreRounding)2398   void setPropertiesFromPattern(String pattern, int ignoreRounding) {
2399     if (pattern == null) {
2400       throw new NullPointerException();
2401     }
2402     PatternStringParser.parseToExistingProperties(pattern, properties, ignoreRounding);
2403   }
2404 
fieldPositionHelper( DecimalQuantity dq, FormattedStringBuilder string, FieldPosition fieldPosition, int offset)2405   static void fieldPositionHelper(
2406           DecimalQuantity dq, FormattedStringBuilder string, FieldPosition fieldPosition, int offset) {
2407       // always return first occurrence:
2408       fieldPosition.setBeginIndex(0);
2409       fieldPosition.setEndIndex(0);
2410       dq.populateUFieldPosition(fieldPosition);
2411       boolean found = FormattedValueStringBuilderImpl.nextFieldPosition(string, fieldPosition);;
2412       if (found && offset != 0) {
2413           fieldPosition.setBeginIndex(fieldPosition.getBeginIndex() + offset);
2414           fieldPosition.setEndIndex(fieldPosition.getEndIndex() + offset);
2415       }
2416   }
2417 
2418   /**
2419    * @deprecated This API is ICU internal only.
2420  * @hide draft / provisional / internal are hidden on OHOS
2421    */
2422   @Deprecated
setProperties(PropertySetter func)2423   public synchronized void setProperties(PropertySetter func) {
2424     func.set(properties);
2425     refreshFormatter();
2426   }
2427 
2428   /**
2429    * @deprecated This API is ICU internal only.
2430  * @hide exposed on OHOS
2431  * @hide draft / provisional / internal are hidden on OHOS
2432    */
2433   @Deprecated
2434   public static interface PropertySetter {
2435     /**
2436      * @deprecated This API is ICU internal only.
2437      * @hide draft / provisional / internal are hidden on OHOS
2438      */
2439     @Deprecated
set(DecimalFormatProperties props)2440     public void set(DecimalFormatProperties props);
2441   }
2442 
2443   /**
2444    * <strong>[icu]</strong> Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to specify pad
2445    * characters inserted before the prefix.
2446    *
2447    * @see #setPadPosition
2448    * @see #getPadPosition
2449    * @see #PAD_AFTER_PREFIX
2450    * @see #PAD_BEFORE_SUFFIX
2451    * @see #PAD_AFTER_SUFFIX
2452    */
2453   public static final int PAD_BEFORE_PREFIX = 0;
2454 
2455   /**
2456    * <strong>[icu]</strong> Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to specify pad
2457    * characters inserted after the prefix.
2458    *
2459    * @see #setPadPosition
2460    * @see #getPadPosition
2461    * @see #PAD_BEFORE_PREFIX
2462    * @see #PAD_BEFORE_SUFFIX
2463    * @see #PAD_AFTER_SUFFIX
2464    */
2465   public static final int PAD_AFTER_PREFIX = 1;
2466 
2467   /**
2468    * <strong>[icu]</strong> Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to specify pad
2469    * characters inserted before the suffix.
2470    *
2471    * @see #setPadPosition
2472    * @see #getPadPosition
2473    * @see #PAD_BEFORE_PREFIX
2474    * @see #PAD_AFTER_PREFIX
2475    * @see #PAD_AFTER_SUFFIX
2476    */
2477   public static final int PAD_BEFORE_SUFFIX = 2;
2478 
2479   /**
2480    * <strong>[icu]</strong> Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to specify pad
2481    * characters inserted after the suffix.
2482    *
2483    * @see #setPadPosition
2484    * @see #getPadPosition
2485    * @see #PAD_BEFORE_PREFIX
2486    * @see #PAD_AFTER_PREFIX
2487    * @see #PAD_BEFORE_SUFFIX
2488    */
2489   public static final int PAD_AFTER_SUFFIX = 3;
2490 }
2491