1 /*
2  *******************************************************************************
3  * Copyright (C) 1996-2014, International Business Machines Corporation and    *
4  * others. All Rights Reserved.                                                *
5  *******************************************************************************
6  */
7 package com.ibm.icu.text;
8 
9 import java.io.IOException;
10 import java.io.ObjectInputStream;
11 import java.io.Serializable;
12 import java.text.ChoiceFormat;
13 import java.util.Arrays;
14 import java.util.Locale;
15 import java.util.MissingResourceException;
16 
17 import com.ibm.icu.impl.CurrencyData;
18 import com.ibm.icu.impl.CurrencyData.CurrencyDisplayInfo;
19 import com.ibm.icu.impl.CurrencyData.CurrencyFormatInfo;
20 import com.ibm.icu.impl.CurrencyData.CurrencySpacingInfo;
21 import com.ibm.icu.impl.ICUCache;
22 import com.ibm.icu.impl.ICUResourceBundle;
23 import com.ibm.icu.impl.SimpleCache;
24 import com.ibm.icu.util.Currency;
25 import com.ibm.icu.util.ICUCloneNotSupportedException;
26 import com.ibm.icu.util.ULocale;
27 import com.ibm.icu.util.ULocale.Category;
28 import com.ibm.icu.util.UResourceBundle;
29 
30 /**
31  * {@icuenhanced java.text.DecimalFormatSymbols}.{@icu _usage_}
32  *
33  * This class represents the set of symbols (such as the decimal separator, the grouping
34  * separator, and so on) needed by <code>DecimalFormat</code> to format
35  * numbers. <code>DecimalFormat</code> creates for itself an instance of
36  * <code>DecimalFormatSymbols</code> from its locale data.  If you need to change any of
37  * these symbols, you can get the <code>DecimalFormatSymbols</code> object from your
38  * <code>DecimalFormat</code> and modify it.
39  *
40  * @see          java.util.Locale
41  * @see          DecimalFormat
42  * @author       Mark Davis
43  * @author       Alan Liu
44  * @stable ICU 2.0
45  */
46 public class DecimalFormatSymbols implements Cloneable, Serializable {
47     /**
48      * Creates a DecimalFormatSymbols object for the default <code>FORMAT</code> locale.
49      * @see Category#FORMAT
50      * @stable ICU 2.0
51      */
DecimalFormatSymbols()52     public DecimalFormatSymbols() {
53         initialize(ULocale.getDefault(Category.FORMAT));
54     }
55 
56     /**
57      * Creates a DecimalFormatSymbols object for the given locale.
58      * @param locale the locale
59      * @stable ICU 2.0
60      */
DecimalFormatSymbols(Locale locale)61     public DecimalFormatSymbols(Locale locale) {
62         initialize(ULocale.forLocale(locale));
63     }
64 
65     /**
66      * {@icu} Creates a DecimalFormatSymbols object for the given locale.
67      * @param locale the locale
68      * @stable ICU 3.2
69      */
DecimalFormatSymbols(ULocale locale)70     public DecimalFormatSymbols(ULocale locale) {
71         initialize(locale);
72     }
73 
74     /**
75      * Returns a DecimalFormatSymbols instance for the default locale.
76      *
77      * <p><strong>Note:</strong> Unlike
78      * <code>java.text.DecimalFormatSymbols#getInstance</code>, this method simply returns
79      * <code>new com.ibm.icu.text.DecimalFormatSymbols()</code>.  ICU currently does not
80      * support <code>DecimalFormatSymbolsProvider</code>, which was introduced in Java 6.
81      *
82      * @return A DecimalFormatSymbols instance.
83      * @stable ICU 3.8
84      */
getInstance()85     public static DecimalFormatSymbols getInstance() {
86         return new DecimalFormatSymbols();
87     }
88 
89     /**
90      * Returns a DecimalFormatSymbols instance for the given locale.
91      *
92      * <p><strong>Note:</strong> Unlike
93      * <code>java.text.DecimalFormatSymbols#getInstance</code>, this method simply returns
94      * <code>new com.ibm.icu.text.DecimalFormatSymbols(locale)</code>.  ICU currently does
95      * not support <code>DecimalFormatSymbolsProvider</code>, which was introduced in Java
96      * 6.
97      *
98      * @param locale the locale.
99      * @return A DecimalFormatSymbols instance.
100      * @stable ICU 3.8
101      */
getInstance(Locale locale)102     public static DecimalFormatSymbols getInstance(Locale locale) {
103         return new DecimalFormatSymbols(locale);
104     }
105 
106     /**
107      * Returns a DecimalFormatSymbols instance for the given locale.
108      *
109      * <p><strong>Note:</strong> Unlike
110      * <code>java.text.DecimalFormatSymbols#getInstance</code>, this method simply returns
111      * <code>new com.ibm.icu.text.DecimalFormatSymbols(locale)</code>.  ICU currently does
112      * not support <code>DecimalFormatSymbolsProvider</code>, which was introduced in Java
113      * 6.
114      *
115      * @param locale the locale.
116      * @return A DecimalFormatSymbols instance.
117      * @stable ICU 3.8
118      */
getInstance(ULocale locale)119     public static DecimalFormatSymbols getInstance(ULocale locale) {
120         return new DecimalFormatSymbols(locale);
121     }
122 
123     /**
124      * Returns an array of all locales for which the <code>getInstance</code> methods of
125      * this class can return localized instances.
126      *
127      * <p><strong>Note:</strong> Unlike
128      * <code>java.text.DecimalFormatSymbols#getAvailableLocales</code>, this method simply
129      * returns the array of <code>Locale</code>s available for this class.  ICU currently
130      * does not support <code>DecimalFormatSymbolsProvider</code>, which was introduced in
131      * Java 6.
132      *
133      * @return An array of <code>Locale</code>s for which localized
134      * <code>DecimalFormatSymbols</code> instances are available.
135      * @stable ICU 3.8
136      */
getAvailableLocales()137     public static Locale[] getAvailableLocales() {
138         return ICUResourceBundle.getAvailableLocales();
139     }
140 
141     /**
142      * {@icu} Returns an array of all locales for which the <code>getInstance</code>
143      * methods of this class can return localized instances.
144      *
145      * <p><strong>Note:</strong> Unlike
146      * <code>java.text.DecimalFormatSymbols#getAvailableLocales</code>, this method simply
147      * returns the array of <code>ULocale</code>s available in this class.  ICU currently
148      * does not support <code>DecimalFormatSymbolsProvider</code>, which was introduced in
149      * Java 6.
150      *
151      * @return An array of <code>ULocale</code>s for which localized
152      * <code>DecimalFormatSymbols</code> instances are available.
153      * @stable ICU 3.8 (retain)
154      * @provisional This API might change or be removed in a future release.
155      */
getAvailableULocales()156     public static ULocale[] getAvailableULocales() {
157         return ICUResourceBundle.getAvailableULocales();
158     }
159 
160 
161     /**
162      * Returns the character used for zero. Different for Arabic, etc.
163      * @return the character
164      * @stable ICU 2.0
165      */
getZeroDigit()166     public char getZeroDigit() {
167         if ( digits != null ) {
168             return digits[0];
169         } else {
170             return zeroDigit;
171         }
172     }
173     /**
174      * Returns the array of characters used as digits, in order from 0 through 9
175      * @return The array
176      * @stable ICU 4.6
177      */
getDigits()178     public char[] getDigits() {
179         if ( digits != null ) {
180             return digits.clone();
181         } else {
182             char [] digitArray = new char[10];
183             for ( int i = 0 ; i < 10 ; i++ ) {
184                 digitArray[i] = (char) (zeroDigit + i);
185             }
186             return digitArray;
187         }
188     }
189 
190     /**
191      * Returns the array of characters used as digits, in order from 0 through 9
192      * Package private method - don't need to defensively copy.
193      * @return The array
194      */
getDigitsLocal()195     char[] getDigitsLocal() {
196         if ( digits != null ) {
197             return digits;
198         } else {
199             char [] digitArray = new char[10];
200             for ( int i = 0 ; i < 10 ; i++ ) {
201                 digitArray[i] = (char) (zeroDigit + i);
202             }
203             return digitArray;
204         }
205     }
206 
207     /**
208      * Sets the character used for zero.
209      * @param zeroDigit the zero character.
210      * @stable ICU 2.0
211      */
setZeroDigit(char zeroDigit)212     public void setZeroDigit(char zeroDigit) {
213         if ( digits != null ) {
214             this.digits[0] = zeroDigit;
215             if (Character.digit(zeroDigit,10) == 0) {
216                 for ( int i = 1 ; i < 10 ; i++ ) {
217                     this.digits[i] = (char)(zeroDigit+i);
218                 }
219             }
220         } else {
221             this.zeroDigit = zeroDigit;
222         }
223     }
224 
225     /**
226      * Returns the character used to represent a significant digit in a pattern.
227      * @return the significant digit pattern character
228      * @stable ICU 3.0
229      */
getSignificantDigit()230     public char getSignificantDigit() {
231         return sigDigit;
232     }
233 
234     /**
235      * Sets the character used to represent a significant digit in a pattern.
236      * @param sigDigit the significant digit pattern character
237      * @stable ICU 3.0
238      */
setSignificantDigit(char sigDigit)239     public void setSignificantDigit(char sigDigit) {
240         this.sigDigit = sigDigit;
241     }
242 
243     /**
244      * Returns the character used for thousands separator. Different for French, etc.
245      * @return the thousands character
246      * @stable ICU 2.0
247      */
getGroupingSeparator()248     public char getGroupingSeparator() {
249         return groupingSeparator;
250     }
251 
252     /**
253      * Sets the character used for thousands separator. Different for French, etc.
254      * @param groupingSeparator the thousands character
255      * @stable ICU 2.0
256      */
setGroupingSeparator(char groupingSeparator)257     public void setGroupingSeparator(char groupingSeparator) {
258         this.groupingSeparator = groupingSeparator;
259     }
260 
261     /**
262      * Returns the character used for decimal sign. Different for French, etc.
263      * @return the decimal character
264      * @stable ICU 2.0
265      */
getDecimalSeparator()266     public char getDecimalSeparator() {
267         return decimalSeparator;
268     }
269 
270     /**
271      * Sets the character used for decimal sign. Different for French, etc.
272      * @param decimalSeparator the decimal character
273      * @stable ICU 2.0
274      */
setDecimalSeparator(char decimalSeparator)275     public void setDecimalSeparator(char decimalSeparator) {
276         this.decimalSeparator = decimalSeparator;
277     }
278 
279     /**
280      * Returns the character used for mille percent sign. Different for Arabic, etc.
281      * @return the mille percent character
282      * @stable ICU 2.0
283      */
getPerMill()284     public char getPerMill() {
285         return perMill;
286     }
287 
288     /**
289      * Sets the character used for mille percent sign. Different for Arabic, etc.
290      * @param perMill the mille percent character
291      * @stable ICU 2.0
292      */
setPerMill(char perMill)293     public void setPerMill(char perMill) {
294         this.perMill = perMill;
295     }
296 
297     /**
298      * Returns the character used for percent sign. Different for Arabic, etc.
299      * @return the percent character
300      * @stable ICU 2.0
301      */
getPercent()302     public char getPercent() {
303         return percent;
304     }
305 
306     /**
307      * Sets the character used for percent sign. Different for Arabic, etc.
308      * @param percent the percent character
309      * @stable ICU 2.0
310      */
setPercent(char percent)311     public void setPercent(char percent) {
312         this.percent = percent;
313     }
314 
315     /**
316      * Returns the character used for a digit in a pattern.
317      * @return the digit pattern character
318      * @stable ICU 2.0
319      */
getDigit()320     public char getDigit() {
321         return digit;
322     }
323 
324     /**
325      * Sets the character used for a digit in a pattern.
326      * @param digit the digit pattern character
327      * @stable ICU 2.0
328      */
setDigit(char digit)329     public void setDigit(char digit) {
330         this.digit = digit;
331     }
332 
333     /**
334      * Returns the character used to separate positive and negative subpatterns
335      * in a pattern.
336      * @return the pattern separator character
337      * @stable ICU 2.0
338      */
getPatternSeparator()339     public char getPatternSeparator() {
340         return patternSeparator;
341     }
342 
343     /**
344      * Sets the character used to separate positive and negative subpatterns
345      * in a pattern.
346      * @param patternSeparator the pattern separator character
347      * @stable ICU 2.0
348      */
setPatternSeparator(char patternSeparator)349     public void setPatternSeparator(char patternSeparator) {
350         this.patternSeparator = patternSeparator;
351     }
352 
353     /**
354      * Returns the String used to represent infinity. Almost always left
355      * unchanged.
356      * @return the Infinity string
357      * @stable ICU 2.0
358      */
359      //Bug 4194173 [Richard/GCL]
360 
getInfinity()361     public String getInfinity() {
362         return infinity;
363     }
364 
365     /**
366      * Sets the String used to represent infinity. Almost always left
367      * unchanged.
368      * @param infinity the Infinity String
369      * @stable ICU 2.0
370      */
setInfinity(String infinity)371     public void setInfinity(String infinity) {
372         this.infinity = infinity;
373     }
374 
375     /**
376      * Returns the String used to represent NaN. Almost always left
377      * unchanged.
378      * @return the NaN String
379      * @stable ICU 2.0
380      */
381      //Bug 4194173 [Richard/GCL]
getNaN()382     public String getNaN() {
383         return NaN;
384     }
385 
386     /**
387      * Sets the String used to represent NaN. Almost always left
388      * unchanged.
389      * @param NaN the NaN String
390      * @stable ICU 2.0
391      */
setNaN(String NaN)392     public void setNaN(String NaN) {
393         this.NaN = NaN;
394     }
395 
396     /**
397      * Returns the character used to represent minus sign. If no explicit
398      * negative format is specified, one is formed by prefixing
399      * minusSign to the positive format.
400      * @return the minus sign character
401      * @stable ICU 2.0
402      */
getMinusSign()403     public char getMinusSign() {
404         return minusSign;
405     }
406 
407     /**
408      * Returns the string used to represent minus sign.
409      * @return the minus sign string
410      * @internal
411      * @deprecated This API is ICU internal only.
412      */
413     @Deprecated
getMinusString()414     public String getMinusString() {
415         return minusString;
416     }
417 
418     /**
419      * Sets the character used to represent minus sign. If no explicit
420      * negative format is specified, one is formed by prefixing
421      * minusSign to the positive format.
422      * @param minusSign the minus sign character
423      * @stable ICU 2.0
424      */
setMinusSign(char minusSign)425     public void setMinusSign(char minusSign) {
426         this.minusSign = minusSign;
427         // Also updates minusString
428         char[] minusArray = { minusSign };
429         minusString = new String(minusArray);
430     }
431 
432     /**
433      * Returns the string denoting the local currency.
434      * @return the local currency String.
435      * @stable ICU 2.0
436      */
getCurrencySymbol()437     public String getCurrencySymbol() {
438         return currencySymbol;
439     }
440 
441     /**
442      * Sets the string denoting the local currency.
443      * @param currency the local currency String.
444      * @stable ICU 2.0
445      */
setCurrencySymbol(String currency)446     public void setCurrencySymbol(String currency) {
447         currencySymbol = currency;
448     }
449 
450     /**
451      * Returns the international string denoting the local currency.
452      * @return the international string denoting the local currency
453      * @stable ICU 2.0
454      */
getInternationalCurrencySymbol()455     public String getInternationalCurrencySymbol() {
456         return intlCurrencySymbol;
457     }
458 
459     /**
460      * Sets the international string denoting the local currency.
461      * @param currency the international string denoting the local currency.
462      * @stable ICU 2.0
463      */
setInternationalCurrencySymbol(String currency)464     public void setInternationalCurrencySymbol(String currency) {
465         intlCurrencySymbol = currency;
466     }
467 
468     /**
469      * Returns the currency symbol, for JDK 1.4 compatibility only.
470      * ICU clients should use the Currency API directly.
471      * @return the currency used, or null
472      * @stable ICU 3.4
473      */
getCurrency()474     public Currency getCurrency() {
475         return currency;
476     }
477 
478     /**
479      * Sets the currency.
480      *
481      * <p><strong>Note:</strong> ICU does not use the DecimalFormatSymbols for the currency
482      * any more.  This API is present for API compatibility only.
483      *
484      * <p>This also sets the currency symbol attribute to the currency's symbol
485      * in the DecimalFormatSymbols' locale, and the international currency
486      * symbol attribute to the currency's ISO 4217 currency code.
487      *
488      * @param currency the new currency to be used
489      * @throws NullPointerException if <code>currency</code> is null
490      * @see #setCurrencySymbol
491      * @see #setInternationalCurrencySymbol
492      *
493      * @stable ICU 3.4
494      */
setCurrency(Currency currency)495     public void setCurrency(Currency currency) {
496         if (currency == null) {
497             throw new NullPointerException();
498         }
499         this.currency = currency;
500         intlCurrencySymbol = currency.getCurrencyCode();
501         currencySymbol = currency.getSymbol(requestedLocale);
502     }
503 
504     /**
505      * Returns the monetary decimal separator.
506      * @return the monetary decimal separator character
507      * @stable ICU 2.0
508      */
getMonetaryDecimalSeparator()509     public char getMonetaryDecimalSeparator() {
510         return monetarySeparator;
511     }
512 
513     /**
514      * {@icu} Returns the monetary grouping separator.
515      * @return the monetary grouping separator character
516      * @stable ICU 3.6
517      */
getMonetaryGroupingSeparator()518     public char getMonetaryGroupingSeparator() {
519         return monetaryGroupingSeparator;
520     }
521 
522     /**
523      * Internal API for NumberFormat
524      * @return String currency pattern string
525      */
getCurrencyPattern()526     String getCurrencyPattern() {
527         return currencyPattern;
528     }
529 
530     /**
531      * Sets the monetary decimal separator.
532      * @param sep the monetary decimal separator character
533      * @stable ICU 2.0
534      */
setMonetaryDecimalSeparator(char sep)535     public void setMonetaryDecimalSeparator(char sep) {
536         monetarySeparator = sep;
537     }
538 
539     /**
540      * Sets the monetary decimal separator.
541      * @param sep the monetary decimal separator character
542      * @stable ICU 3.6
543      */
setMonetaryGroupingSeparator(char sep)544     public void setMonetaryGroupingSeparator(char sep) {
545         monetaryGroupingSeparator = sep;
546     }
547 
548     /**
549     * Returns the multiplication sign
550     * @draft ICU 54
551     * @provisional This API might change or be removed in a future release.
552     */
getExponentMultiplicationSign()553     public String getExponentMultiplicationSign() {
554         return exponentMultiplicationSign;
555     }
556 
557     /**
558     * Sets the multiplication sign
559     * @draft ICU 54
560     * @provisional This API might change or be removed in a future release.
561     */
setExponentMultiplicationSign(String exponentMultiplicationSign)562     public void setExponentMultiplicationSign(String exponentMultiplicationSign) {
563         this.exponentMultiplicationSign = exponentMultiplicationSign;
564     }
565 
566     /**
567      * {@icu} Returns the string used to separate the mantissa from the exponent.
568      * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
569      * @return the localized exponent symbol, used in localized patterns
570      * and formatted strings
571      * @see #setExponentSeparator
572      * @stable ICU 2.0
573      */
getExponentSeparator()574     public String getExponentSeparator() {
575         return exponentSeparator;
576     }
577 
578     /**
579      * {@icu} Sets the string used to separate the mantissa from the exponent.
580      * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
581      * @param exp the localized exponent symbol, used in localized patterns
582      * and formatted strings
583      * @see #getExponentSeparator
584      * @stable ICU 2.0
585      */
setExponentSeparator(String exp)586     public void setExponentSeparator(String exp) {
587         exponentSeparator = exp;
588     }
589 
590     /**
591      * {@icu} Returns the localized plus sign.
592      * @return the plus sign, used in localized patterns and formatted
593      * strings
594      * @see #setPlusSign
595      * @see #setMinusSign
596      * @see #getMinusSign
597      * @stable ICU 2.0
598      */
getPlusSign()599     public char getPlusSign() {
600         return plusSign;
601     }
602 
603     /**
604      * Returns the string used to represent plus sign.
605      * @return the plus sign string
606      * @internal
607      * @deprecated This API is ICU internal only.
608      */
609     @Deprecated
getPlusString()610     public String getPlusString() {
611         return plusString;
612     }
613 
614     /**
615      * {@icu} Sets the localized plus sign.
616      * @param plus the plus sign, used in localized patterns and formatted
617      * strings
618      * @see #getPlusSign
619      * @see #setMinusSign
620      * @see #getMinusSign
621      * @stable ICU 2.0
622      */
setPlusSign(char plus)623     public void setPlusSign(char plus) {
624         plusSign = plus;
625         // Also updates plusString
626         char[] plusArray = { plusSign };
627         plusString = new String(plusArray);
628     }
629 
630     /**
631      * {@icu} Returns the character used to pad numbers out to a specified width.  This is
632      * not the pad character itself; rather, it is the special pattern character
633      * <em>preceding</em> the pad character.  In the pattern "*_#,##0", '*' is the pad
634      * escape, and '_' is the pad character.
635      * @return the character
636      * @see #setPadEscape
637      * @see DecimalFormat#getFormatWidth
638      * @see DecimalFormat#getPadPosition
639      * @see DecimalFormat#getPadCharacter
640      * @stable ICU 2.0
641      */
getPadEscape()642     public char getPadEscape() {
643         return padEscape;
644     }
645 
646     /**
647      * {@icu} Sets the character used to pad numbers out to a specified width.  This is not
648      * the pad character itself; rather, it is the special pattern character
649      * <em>preceding</em> the pad character.  In the pattern "*_#,##0", '*' is the pad
650      * escape, and '_' is the pad character.
651      * @see #getPadEscape
652      * @see DecimalFormat#setFormatWidth
653      * @see DecimalFormat#setPadPosition
654      * @see DecimalFormat#setPadCharacter
655      * @stable ICU 2.0
656      */
setPadEscape(char c)657     public void setPadEscape(char c) {
658         padEscape = c;
659     }
660 
661     /**
662      * {@icu} Indicates the currency match pattern used in {@link #getPatternForCurrencySpacing}.
663      * @stable ICU 4.2
664      */
665     public static final int CURRENCY_SPC_CURRENCY_MATCH = 0;
666 
667     /**
668      * {@icu} Indicates the surrounding match pattern used in {@link
669      * #getPatternForCurrencySpacing}.
670      * @stable ICU 4.2
671      */
672     public static final int CURRENCY_SPC_SURROUNDING_MATCH = 1;
673 
674     /**
675      * {@icu} Indicates the insertion value used in {@link #getPatternForCurrencySpacing}.
676      * @stable ICU 4.4
677      */
678     public static final int CURRENCY_SPC_INSERT = 2;
679 
680     private String[] currencySpcBeforeSym;
681     private String[] currencySpcAfterSym;
682 
683     /**
684      * {@icu} Returns the desired currency spacing value. Original values come from ICU's
685      * CLDR data based on the locale provided during construction, and can be null.  These
686      * values govern what and when text is inserted between a currency code/name/symbol
687      * and the currency amount when formatting money.
688      *
689      * <p>For more information, see <a href="http://www.unicode.org/reports/tr35/#Currencies"
690      * >UTS#35 section 5.10.2</a>.
691      *
692      * <p><strong>Note:</strong> ICU4J does not currently use this information.
693      *
694      * @param itemType one of CURRENCY_SPC_CURRENCY_MATCH, CURRENCY_SPC_SURROUNDING_MATCH
695      * or CURRENCY_SPC_INSERT
696      * @param beforeCurrency true to get the <code>beforeCurrency</code> values, false
697      * to get the <code>afterCurrency</code> values.
698      * @return the value, or null.
699      * @see #setPatternForCurrencySpacing(int, boolean, String)
700      * @stable ICU 4.2
701      */
getPatternForCurrencySpacing(int itemType, boolean beforeCurrency)702     public String getPatternForCurrencySpacing(int itemType, boolean beforeCurrency)  {
703         if (itemType < CURRENCY_SPC_CURRENCY_MATCH ||
704             itemType > CURRENCY_SPC_INSERT ) {
705             throw new IllegalArgumentException("unknown currency spacing: " + itemType);
706         }
707         if (beforeCurrency) {
708             return currencySpcBeforeSym[itemType];
709         }
710         return currencySpcAfterSym[itemType];
711     }
712 
713     /**
714      * {@icu} Sets the indicated currency spacing pattern or value. See {@link
715      * #getPatternForCurrencySpacing} for more information.
716      *
717      * <p>Values for currency match and surrounding match must be {@link
718      * com.ibm.icu.text.UnicodeSet} patterns. Values for insert can be any string.
719      *
720      * <p><strong>Note:</strong> ICU4J does not currently use this information.
721      *
722      * @param itemType one of CURRENCY_SPC_CURRENCY_MATCH, CURRENCY_SPC_SURROUNDING_MATCH
723      * or CURRENCY_SPC_INSERT
724      * @param beforeCurrency true if the pattern is for before the currency symbol.
725      * false if the pattern is for after it.
726      * @param  pattern string to override current setting; can be null.
727      * @see #getPatternForCurrencySpacing(int, boolean)
728      * @stable ICU 4.2
729      */
setPatternForCurrencySpacing(int itemType, boolean beforeCurrency, String pattern)730     public void setPatternForCurrencySpacing(int itemType, boolean beforeCurrency, String pattern) {
731         if (itemType < CURRENCY_SPC_CURRENCY_MATCH ||
732             itemType > CURRENCY_SPC_INSERT ) {
733             throw new IllegalArgumentException("unknown currency spacing: " + itemType);
734         }
735         if (beforeCurrency) {
736             currencySpcBeforeSym[itemType] = pattern;
737         } else {
738             currencySpcAfterSym[itemType] = pattern;
739         }
740     }
741 
742     /**
743      * Returns the locale for which this object was constructed.
744      * @return the locale for which this object was constructed
745      * @stable ICU 2.0
746      */
getLocale()747     public Locale getLocale() {
748         return requestedLocale;
749     }
750 
751     /**
752      * Returns the locale for which this object was constructed.
753      * @return the locale for which this object was constructed
754      * @stable ICU 3.2
755      */
getULocale()756     public ULocale getULocale() {
757         return ulocale;
758     }
759 
760     /**
761      * {@inheritDoc}
762      * @stable ICU 2.0
763      */
clone()764     public Object clone() {
765         try {
766             return (DecimalFormatSymbols) super.clone();
767             // other fields are bit-copied
768         } catch (CloneNotSupportedException e) {
769             ///CLOVER:OFF
770             throw new ICUCloneNotSupportedException(e);
771             ///CLOVER:ON
772         }
773     }
774 
775     /**
776      * {@inheritDoc}
777      * @stable ICU 2.0
778      */
equals(Object obj)779     public boolean equals(Object obj) {
780         if (!(obj instanceof DecimalFormatSymbols)) {
781             return false;
782         }
783         if (this == obj) {
784             return true;
785         }
786         DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
787         for (int i = 0; i <= CURRENCY_SPC_INSERT; i++) {
788             if (!currencySpcBeforeSym[i].equals(other.currencySpcBeforeSym[i])) {
789                 return false;
790             }
791             if (!currencySpcAfterSym[i].equals(other.currencySpcAfterSym[i])) {
792                 return false;
793             }
794         }
795 
796         if ( other.digits == null ) {
797             for (int i = 0 ; i < 10 ; i++) {
798                 if (digits[i] != other.zeroDigit + i) {
799                     return false;
800                 }
801             }
802         } else if (!Arrays.equals(digits,other.digits)) {
803                     return false;
804         }
805 
806         return (
807         groupingSeparator == other.groupingSeparator &&
808         decimalSeparator == other.decimalSeparator &&
809         percent == other.percent &&
810         perMill == other.perMill &&
811         digit == other.digit &&
812         minusSign == other.minusSign &&
813         minusString.equals(other.minusString) &&
814         patternSeparator == other.patternSeparator &&
815         infinity.equals(other.infinity) &&
816         NaN.equals(other.NaN) &&
817         currencySymbol.equals(other.currencySymbol) &&
818         intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
819         padEscape == other.padEscape &&
820         plusSign == other.plusSign &&
821         plusString.equals(other.plusString) &&
822         exponentSeparator.equals(other.exponentSeparator) &&
823         monetarySeparator == other.monetarySeparator &&
824         monetaryGroupingSeparator == other.monetaryGroupingSeparator &&
825         exponentMultiplicationSign.equals(other.exponentMultiplicationSign));
826     }
827 
828     /**
829      * {@inheritDoc}
830      * @stable ICU 2.0
831      */
hashCode()832     public int hashCode() {
833             int result = digits[0];
834             result = result * 37 + groupingSeparator;
835             result = result * 37 + decimalSeparator;
836             return result;
837     }
838 
839     /**
840      * Check for bidi marks: LRM, RLM, ALM
841      */
isBidiMark(char c)842     private static boolean isBidiMark(char c) {
843         return (c=='\u200E' || c=='\u200F' || c=='\u061C');
844     }
845 
846     /**
847      * Initializes the symbols from the LocaleElements resource bundle.
848      * Note: The organization of LocaleElements badly needs to be
849      * cleaned up.
850      */
initialize( ULocale locale )851     private void initialize( ULocale locale ) {
852         this.requestedLocale = locale.toLocale();
853         this.ulocale = locale;
854 
855         String nsName;
856         // Attempt to set the zero digit based on the numbering system for the locale requested
857         NumberingSystem ns = NumberingSystem.getInstance(locale);
858         digits = new char[10];
859         if ( ns != null && ns.getRadix() == 10 && !ns.isAlgorithmic() &&
860              NumberingSystem.isValidDigitString(ns.getDescription())) {
861             String digitString = ns.getDescription();
862             digits[0] = digitString.charAt(0);
863             digits[1] = digitString.charAt(1);
864             digits[2] = digitString.charAt(2);
865             digits[3] = digitString.charAt(3);
866             digits[4] = digitString.charAt(4);
867             digits[5] = digitString.charAt(5);
868             digits[6] = digitString.charAt(6);
869             digits[7] = digitString.charAt(7);
870             digits[8] = digitString.charAt(8);
871             digits[9] = digitString.charAt(9);
872             nsName = ns.getName();
873         } else {
874             digits[0] = DecimalFormat.PATTERN_ZERO_DIGIT;
875             digits[1] = DecimalFormat.PATTERN_ONE_DIGIT;
876             digits[2] = DecimalFormat.PATTERN_TWO_DIGIT;
877             digits[3] = DecimalFormat.PATTERN_THREE_DIGIT;
878             digits[4] = DecimalFormat.PATTERN_FOUR_DIGIT;
879             digits[5] = DecimalFormat.PATTERN_FIVE_DIGIT;
880             digits[6] = DecimalFormat.PATTERN_SIX_DIGIT;
881             digits[7] = DecimalFormat.PATTERN_SEVEN_DIGIT;
882             digits[8] = DecimalFormat.PATTERN_EIGHT_DIGIT;
883             digits[9] = DecimalFormat.PATTERN_NINE_DIGIT;
884             nsName = "latn"; // Default numbering system
885         }
886 
887         /* try the cache first */
888         String[][] data = cachedLocaleData.get(locale);
889         String[] numberElements;
890         if (data == null) {  /* cache miss */
891             data = new String[1][];
892             ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.
893                 getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale);
894             boolean isLatn = nsName.equals("latn");
895             String baseKey = "NumberElements/" + nsName + "/symbols/";
896             String latnKey = "NumberElements/latn/symbols/";
897             String[] symbolKeys = { "decimal", "group", "list", "percentSign", "minusSign", "plusSign", "exponential", "perMille", "infinity", "nan", "currencyDecimal", "currencyGroup", "superscriptingExponent" };
898             String[] fallbackElements = { ".", ",", ";", "%", "-", "+", "E", "\u2030", "\u221e", "NaN", null, null };
899             String[] symbolsArray = new String[symbolKeys.length];
900             for ( int i = 0 ; i < symbolKeys.length; i++ ) {
901                 try {
902                     symbolsArray[i] = rb.getStringWithFallback(baseKey+symbolKeys[i]);
903                 } catch (MissingResourceException ex) {
904                     if (!isLatn) { // Fall back to latn numbering system for symbols if desired symbol isn't found.
905                         try {
906                             symbolsArray[i] = rb.getStringWithFallback(latnKey+symbolKeys[i]);
907                         } catch (MissingResourceException ex1) {
908                             symbolsArray[i] = fallbackElements[i];
909                         }
910                     } else {
911                         symbolsArray[i] = fallbackElements[i];
912                     }
913                 }
914             }
915 
916             data[0] = symbolsArray;
917             /* update cache */
918             cachedLocaleData.put(locale, data);
919         }
920         numberElements = data[0];
921 
922         ICUResourceBundle r = (ICUResourceBundle)UResourceBundle.
923             getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale);
924 
925         // TODO: Determine actual and valid locale correctly.
926         ULocale uloc = r.getULocale();
927         setLocale(uloc, uloc);
928 
929 
930         decimalSeparator = numberElements[0].charAt(0);
931         groupingSeparator = numberElements[1].charAt(0);
932         patternSeparator = numberElements[2].charAt(0);
933         percent = numberElements[3].charAt(0);
934         minusString = numberElements[4];
935         minusSign = (minusString.length() > 1 && isBidiMark(minusString.charAt(0)))? minusString.charAt(1): minusString.charAt(0);
936         plusString = numberElements[5];
937         plusSign = (plusString.length() > 1 && isBidiMark(plusString.charAt(0)))? plusString.charAt(1): plusString.charAt(0);
938         exponentSeparator = numberElements[6];
939         perMill = numberElements[7].charAt(0);
940         infinity = numberElements[8];
941         NaN = numberElements[9];
942 
943         if ( numberElements[10] != null) {
944             monetarySeparator = numberElements[10].charAt(0);
945         } else {
946             monetarySeparator = decimalSeparator;
947         }
948 
949         if ( numberElements[11] != null) {
950             monetaryGroupingSeparator = numberElements[11].charAt(0);
951         } else {
952             monetaryGroupingSeparator = groupingSeparator;
953         }
954 
955         if ( numberElements[12] != null) {
956             exponentMultiplicationSign = numberElements[12];
957         } else {
958             exponentMultiplicationSign = "\u00D7";
959         }
960 
961         digit = DecimalFormat.PATTERN_DIGIT;  // Localized pattern character no longer in CLDR
962         padEscape = DecimalFormat.PATTERN_PAD_ESCAPE;
963         sigDigit  = DecimalFormat.PATTERN_SIGNIFICANT_DIGIT;
964 
965 
966         CurrencyDisplayInfo info = CurrencyData.provider.getInstance(locale, true);
967 
968         // Obtain currency data from the currency API.  This is strictly
969         // for backward compatibility; we don't use DecimalFormatSymbols
970         // for currency data anymore.
971         String currname = null;
972         currency = Currency.getInstance(locale);
973         if (currency != null) {
974             intlCurrencySymbol = currency.getCurrencyCode();
975             boolean[] isChoiceFormat = new boolean[1];
976             currname = currency.getName(locale, Currency.SYMBOL_NAME, isChoiceFormat);
977             // If this is a ChoiceFormat currency, then format an
978             // arbitrary value; pick something != 1; more common.
979             currencySymbol = isChoiceFormat[0]
980                 ? new ChoiceFormat(currname).format(2.0)
981                 : currname;
982             CurrencyFormatInfo fmtInfo = info.getFormatInfo(intlCurrencySymbol);
983             if (fmtInfo != null) {
984                 currencyPattern = fmtInfo.currencyPattern;
985                 monetarySeparator = fmtInfo.monetarySeparator;
986                 monetaryGroupingSeparator = fmtInfo.monetaryGroupingSeparator;
987             }
988         } else {
989             intlCurrencySymbol = "XXX";
990             currencySymbol = "\u00A4"; // 'OX' currency symbol
991         }
992 
993 
994         // Get currency spacing data.
995         currencySpcBeforeSym = new String[3];
996         currencySpcAfterSym = new String[3];
997         initSpacingInfo(info.getSpacingInfo());
998     }
999 
initSpacingInfo(CurrencySpacingInfo spcInfo)1000     private void initSpacingInfo(CurrencySpacingInfo spcInfo) {
1001         currencySpcBeforeSym[CURRENCY_SPC_CURRENCY_MATCH] = spcInfo.beforeCurrencyMatch;
1002         currencySpcBeforeSym[CURRENCY_SPC_SURROUNDING_MATCH] = spcInfo.beforeContextMatch;
1003         currencySpcBeforeSym[CURRENCY_SPC_INSERT] = spcInfo.beforeInsert;
1004         currencySpcAfterSym[CURRENCY_SPC_CURRENCY_MATCH] = spcInfo.afterCurrencyMatch;
1005         currencySpcAfterSym[CURRENCY_SPC_SURROUNDING_MATCH] = spcInfo.afterContextMatch;
1006         currencySpcAfterSym[CURRENCY_SPC_INSERT] = spcInfo.afterInsert;
1007     }
1008 
1009     /**
1010      * Reads the default serializable fields, then if <code>serialVersionOnStream</code>
1011      * is less than 1, initialize <code>monetarySeparator</code> to be
1012      * the same as <code>decimalSeparator</code> and <code>exponential</code>
1013      * to be 'E'.
1014      * Finally, sets serialVersionOnStream back to the maximum allowed value so that
1015      * default serialization will work properly if this object is streamed out again.
1016      */
readObject(ObjectInputStream stream)1017     private void readObject(ObjectInputStream stream)
1018         throws IOException, ClassNotFoundException {
1019 
1020         // TODO: it looks to me {dlf} that the serialization code was never updated
1021         // to handle the actual/valid ulocale fields.
1022 
1023         stream.defaultReadObject();
1024         ///CLOVER:OFF
1025         // we don't have data for these old serialized forms any more
1026         if (serialVersionOnStream < 1) {
1027             // Didn't have monetarySeparator or exponential field;
1028             // use defaults.
1029             monetarySeparator = decimalSeparator;
1030             exponential = 'E';
1031         }
1032         if (serialVersionOnStream < 2) {
1033             padEscape = DecimalFormat.PATTERN_PAD_ESCAPE;
1034             plusSign = DecimalFormat.PATTERN_PLUS_SIGN;
1035             exponentSeparator = String.valueOf(exponential);
1036             // Although we read the exponential field on stream to create the
1037             // exponentSeparator, we don't do the reverse, since scientific
1038             // notation isn't supported by the old classes, even though the
1039             // symbol is there.
1040         }
1041         ///CLOVER:ON
1042         if (serialVersionOnStream < 3) {
1043             // Resurrected objects from old streams will have no
1044             // locale.  There is no 100% fix for this.  A
1045             // 90% fix is to construct a mapping of data back to
1046             // locale, perhaps a hash of all our members.  This is
1047             // expensive and doesn't seem worth it.
1048             requestedLocale = Locale.getDefault();
1049         }
1050         if (serialVersionOnStream < 4) {
1051             // use same default behavior as for versions with no Locale
1052             ulocale = ULocale.forLocale(requestedLocale);
1053         }
1054         if (serialVersionOnStream < 5) {
1055             // use the same one for groupingSeparator
1056             monetaryGroupingSeparator = groupingSeparator;
1057         }
1058         if (serialVersionOnStream < 6) {
1059             // Set null to CurrencySpacing related fields.
1060             if (currencySpcBeforeSym == null) {
1061                 currencySpcBeforeSym = new String[CURRENCY_SPC_INSERT+1];
1062             }
1063             if (currencySpcAfterSym == null) {
1064                 currencySpcAfterSym = new String[CURRENCY_SPC_INSERT+1];
1065             }
1066             initSpacingInfo(CurrencyData.CurrencySpacingInfo.DEFAULT);
1067         }
1068         if (serialVersionOnStream < 7) {
1069             // Set minusString,plusString from minusSign,plusSign
1070             if (minusString == null) {
1071                 char[] minusArray = { minusSign };
1072                 minusString = new String(minusArray);
1073             }
1074             if (plusString == null) {
1075                 char[] plusArray = { plusSign };
1076                 plusString = new String(plusArray);
1077             }
1078         }
1079         if (serialVersionOnStream < 8) {
1080             if (exponentMultiplicationSign == null) {
1081                 exponentMultiplicationSign = "\u00D7";
1082             }
1083         }
1084         serialVersionOnStream = currentSerialVersion;
1085 
1086     // recreate
1087     currency = Currency.getInstance(intlCurrencySymbol);
1088     }
1089 
1090     /**
1091      * Character used for zero.  This remains only for backward compatibility
1092      * purposes.  The digits array below is now used to actively store the digits.
1093      *
1094      * @serial
1095      * @see #getZeroDigit
1096      */
1097     private  char    zeroDigit;
1098 
1099     /**
1100      * Array of characters used for the digits 0-9 in order.
1101      *
1102      */
1103     private  char    digits[];
1104 
1105     /**
1106      * Character used for thousands separator.
1107      *
1108      * @serial
1109      * @see #getGroupingSeparator
1110      */
1111     private  char    groupingSeparator;
1112 
1113     /**
1114      * Character used for decimal sign.
1115      *
1116      * @serial
1117      * @see #getDecimalSeparator
1118      */
1119     private  char    decimalSeparator;
1120 
1121     /**
1122      * Character used for mille percent sign.
1123      *
1124      * @serial
1125      * @see #getPerMill
1126      */
1127     private  char    perMill;
1128 
1129     /**
1130      * Character used for percent sign.
1131      * @serial
1132      * @see #getPercent
1133      */
1134     private  char    percent;
1135 
1136     /**
1137      * Character used for a digit in a pattern.
1138      *
1139      * @serial
1140      * @see #getDigit
1141      */
1142     private  char    digit;
1143 
1144     /**
1145      * Character used for a significant digit in a pattern.
1146      *
1147      * @serial
1148      * @see #getSignificantDigit
1149      */
1150     private  char    sigDigit;
1151 
1152     /**
1153      * Character used to separate positive and negative subpatterns
1154      * in a pattern.
1155      *
1156      * @serial
1157      * @see #getPatternSeparator
1158      */
1159     private  char    patternSeparator;
1160 
1161     /**
1162      * Character used to represent infinity.
1163      * @serial
1164      * @see #getInfinity
1165      */
1166     private  String  infinity;
1167 
1168     /**
1169      * Character used to represent NaN.
1170      * @serial
1171      * @see #getNaN
1172      */
1173     private  String  NaN;
1174 
1175     /**
1176      * Character used to represent minus sign.
1177      * @serial
1178      * @see #getMinusSign
1179      */
1180     private  char    minusSign;
1181 
1182     /**
1183      * String denoting the local currency, e.g. "$".
1184      * @serial
1185      * @see #getCurrencySymbol
1186      */
1187     private  String  currencySymbol;
1188 
1189     /**
1190      * International string denoting the local currency, e.g. "USD".
1191      * @serial
1192      * @see #getInternationalCurrencySymbol
1193      */
1194     private  String  intlCurrencySymbol;
1195 
1196     /**
1197      * The decimal separator used when formatting currency values.
1198      * @serial
1199      * @see #getMonetaryDecimalSeparator
1200      */
1201     private  char    monetarySeparator; // Field new in JDK 1.1.6
1202 
1203     /**
1204      * The decimal separator used when formatting currency values.
1205      * @serial
1206      * @see #getMonetaryGroupingSeparator
1207      */
1208     private  char    monetaryGroupingSeparator; // Field new in JDK 1.1.6
1209 
1210     /**
1211      * The character used to distinguish the exponent in a number formatted
1212      * in exponential notation, e.g. 'E' for a number such as "1.23E45".
1213      * <p>
1214      * Note that this field has been superseded by <code>exponentSeparator</code>.
1215      * It is retained for backward compatibility.
1216      *
1217      * @serial
1218      */
1219     private  char    exponential;       // Field new in JDK 1.1.6
1220 
1221     /**
1222      * The string used to separate the mantissa from the exponent.
1223      * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
1224      * <p>
1225      * Note that this supersedes the <code>exponential</code> field.
1226      *
1227      * @serial
1228      * @since AlphaWorks
1229      */
1230     private String exponentSeparator;
1231 
1232     /**
1233      * The character used to indicate a padding character in a format,
1234      * e.g., '*' in a pattern such as "$*_#,##0.00".
1235      * @serial
1236      * @since AlphaWorks
1237      */
1238     private char padEscape;
1239 
1240     /**
1241      * The character used to indicate a plus sign.
1242      * @serial
1243      * @since AlphaWorks
1244      */
1245     private char plusSign;
1246 
1247     /**
1248      * The locale for which this object was constructed.  Set to the
1249      * default locale for objects resurrected from old streams.
1250      * @since ICU 2.2
1251      */
1252     private Locale requestedLocale;
1253 
1254     /**
1255      * The requested ULocale.  We keep the old locale for serialization compatibility.
1256      * @since ICU 3.2
1257      */
1258     private ULocale ulocale;
1259 
1260     /**
1261      * String versions of some number symbols.
1262      * @serial
1263      * @since ICU 52
1264      */
1265     private String minusString = null;
1266     private String plusString = null;
1267 
1268     /**
1269      * Exponent multiplication sign. e.g "x"
1270      * @serial
1271      * @since ICU 54
1272      */
1273     private String exponentMultiplicationSign = null;
1274 
1275     // Proclaim JDK 1.1 FCS compatibility
1276     private static final long serialVersionUID = 5772796243397350300L;
1277 
1278     // The internal serial version which says which version was written
1279     // - 0 (default) for version up to JDK 1.1.5
1280     // - 1 for version from JDK 1.1.6, which includes two new fields:
1281     //     monetarySeparator and exponential.
1282     // - 2 for version from AlphaWorks, which includes 3 new fields:
1283     //     padEscape, exponentSeparator, and plusSign.
1284     // - 3 for ICU 2.2, which includes the locale field
1285     // - 4 for ICU 3.2, which includes the ULocale field
1286     // - 5 for ICU 3.6, which includes the monetaryGroupingSeparator field
1287     // - 6 for ICU 4.2, which includes the currencySpc* fields
1288     // - 7 for ICU 52, which includes the minusString and plusString fields
1289     // - 8 for ICU 54, which includes exponentMultiplicationSign field.
1290     private static final int currentSerialVersion = 8;
1291 
1292     /**
1293      * Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
1294      * Possible values are:
1295      * <ul>
1296      * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
1297      *
1298      * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which includes
1299      *      two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
1300      * <li><b>2</b>: Version for AlphaWorks.  Adds padEscape, exponentSeparator,
1301      *      and plusSign.
1302      * <li><b>3</b>: Version for ICU 2.2, which adds locale.
1303      * <li><b>4</b>: Version for ICU 3.2, which adds ulocale.
1304      * <li><b>5</b>: Version for ICU 3.6, which adds monetaryGroupingSeparator.
1305      * <li><b>6</b>: Version for ICU 4.2, which adds currencySpcBeforeSym and
1306      *      currencySpcAfterSym.
1307      * <li><b>7</b>: Version for ICU 52, which adds minusString and plusString.
1308      * </ul>
1309      * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
1310      * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
1311      * is always written.
1312      *
1313      * @serial
1314      */
1315     private int serialVersionOnStream = currentSerialVersion;
1316 
1317     /**
1318      * cache to hold the NumberElements of a Locale.
1319      */
1320     private static final ICUCache<ULocale, String[][]> cachedLocaleData =
1321         new SimpleCache<ULocale, String[][]>();
1322 
1323     /**
1324      *
1325      */
1326     private String  currencyPattern = null;
1327 
1328     // -------- BEGIN ULocale boilerplate --------
1329 
1330     /**
1331      * {@icu} Returns the locale that was used to create this object, or null.
1332      * This may may differ from the locale requested at the time of
1333      * this object's creation.  For example, if an object is created
1334      * for locale <tt>en_US_CALIFORNIA</tt>, the actual data may be
1335      * drawn from <tt>en</tt> (the <i>actual</i> locale), and
1336      * <tt>en_US</tt> may be the most specific locale that exists (the
1337      * <i>valid</i> locale).
1338      *
1339      * <p>Note: The <i>actual</i> locale is returned correctly, but the <i>valid</i>
1340      * locale is not, in most cases.
1341      * @param type type of information requested, either {@link
1342      * com.ibm.icu.util.ULocale#VALID_LOCALE} or {@link
1343      * com.ibm.icu.util.ULocale#ACTUAL_LOCALE}.
1344      * @return the information specified by <i>type</i>, or null if
1345      * this object was not constructed from locale data.
1346      * @see com.ibm.icu.util.ULocale
1347      * @see com.ibm.icu.util.ULocale#VALID_LOCALE
1348      * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE
1349      * @draft ICU 2.8 (retain)
1350      * @provisional This API might change or be removed in a future release.
1351      */
getLocale(ULocale.Type type)1352     public final ULocale getLocale(ULocale.Type type) {
1353         return type == ULocale.ACTUAL_LOCALE ?
1354             this.actualLocale : this.validLocale;
1355     }
1356 
1357     /**
1358      * {@icu} Sets information about the locales that were used to create this
1359      * object.  If the object was not constructed from locale data,
1360      * both arguments should be set to null.  Otherwise, neither
1361      * should be null.  The actual locale must be at the same level or
1362      * less specific than the valid locale.  This method is intended
1363      * for use by factories or other entities that create objects of
1364      * this class.
1365      * @param valid the most specific locale containing any resource
1366      * data, or null
1367      * @param actual the locale containing data used to construct this
1368      * object, or null
1369      * @see com.ibm.icu.util.ULocale
1370      * @see com.ibm.icu.util.ULocale#VALID_LOCALE
1371      * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE
1372      */
setLocale(ULocale valid, ULocale actual)1373     final void setLocale(ULocale valid, ULocale actual) {
1374         // Change the following to an assertion later
1375         if ((valid == null) != (actual == null)) {
1376             ///CLOVER:OFF
1377             throw new IllegalArgumentException();
1378             ///CLOVER:ON
1379         }
1380         // Another check we could do is that the actual locale is at
1381         // the same level or less specific than the valid locale.
1382         this.validLocale = valid;
1383         this.actualLocale = actual;
1384     }
1385 
1386     /**
1387      * The most specific locale containing any resource data, or null.
1388      * @see com.ibm.icu.util.ULocale
1389      */
1390     private ULocale validLocale;
1391 
1392     /**
1393      * The locale containing data used to construct this object, or
1394      * null.
1395      * @see com.ibm.icu.util.ULocale
1396      */
1397     private ULocale actualLocale;
1398 
1399     // not serialized, reconstructed from intlCurrencyCode
1400     private transient Currency currency;
1401 
1402     // -------- END ULocale boilerplate --------
1403 }
1404