< prev index next >

src/java.base/share/classes/java/util/Locale.java

Print this page
rev 52979 : 8215281: Use String.isEmpty() when applicable in java.base
Reviewed-by: TBD


1379      * previous uses of <code>toString</code> that expected language, country, and variant
1380      * fields only.  To represent a Locale as a String for interchange purposes, use
1381      * {@link #toLanguageTag}.
1382      *
1383      * <p>Examples: <ul>
1384      * <li>{@code en}</li>
1385      * <li>{@code de_DE}</li>
1386      * <li>{@code _GB}</li>
1387      * <li>{@code en_US_WIN}</li>
1388      * <li>{@code de__POSIX}</li>
1389      * <li>{@code zh_CN_#Hans}</li>
1390      * <li>{@code zh_TW_#Hant_x-java}</li>
1391      * <li>{@code th_TH_TH_#u-nu-thai}</li></ul>
1392      *
1393      * @return A string representation of the Locale, for debugging.
1394      * @see #getDisplayName
1395      * @see #toLanguageTag
1396      */
1397     @Override
1398     public final String toString() {
1399         boolean l = (baseLocale.getLanguage().length() != 0);
1400         boolean s = (baseLocale.getScript().length() != 0);
1401         boolean r = (baseLocale.getRegion().length() != 0);
1402         boolean v = (baseLocale.getVariant().length() != 0);
1403         boolean e = (localeExtensions != null && localeExtensions.getID().length() != 0);
1404 
1405         StringBuilder result = new StringBuilder(baseLocale.getLanguage());
1406         if (r || (l && (v || s || e))) {
1407             result.append('_')
1408                 .append(baseLocale.getRegion()); // This may just append '_'
1409         }
1410         if (v && (l || r)) {
1411             result.append('_')
1412                 .append(baseLocale.getVariant());
1413         }
1414 
1415         if (s && (l || r)) {
1416             result.append("_#")
1417                 .append(baseLocale.getScript());
1418         }
1419 
1420         if (e && (l || r)) {
1421             result.append('_');
1422             if (!s) {
1423                 result.append('#');


1487      * <pre>
1488      *   new Locale("xx", "YY").toLanguageTag();</pre>
1489      *
1490      * will return "xx-YY", but the language subtag "xx" and the
1491      * region subtag "YY" are invalid because they are not registered
1492      * in the IANA Language Subtag Registry.
1493      *
1494      * @return a BCP47 language tag representing the locale
1495      * @see #forLanguageTag(String)
1496      * @since 1.7
1497      */
1498     public String toLanguageTag() {
1499         if (languageTag != null) {
1500             return languageTag;
1501         }
1502 
1503         LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
1504         StringBuilder buf = new StringBuilder();
1505 
1506         String subtag = tag.getLanguage();
1507         if (subtag.length() > 0) {
1508             buf.append(LanguageTag.canonicalizeLanguage(subtag));
1509         }
1510 
1511         subtag = tag.getScript();
1512         if (subtag.length() > 0) {
1513             buf.append(LanguageTag.SEP);
1514             buf.append(LanguageTag.canonicalizeScript(subtag));
1515         }
1516 
1517         subtag = tag.getRegion();
1518         if (subtag.length() > 0) {
1519             buf.append(LanguageTag.SEP);
1520             buf.append(LanguageTag.canonicalizeRegion(subtag));
1521         }
1522 
1523         List<String>subtags = tag.getVariants();
1524         for (String s : subtags) {
1525             buf.append(LanguageTag.SEP);
1526             // preserve casing
1527             buf.append(s);
1528         }
1529 
1530         subtags = tag.getExtensions();
1531         for (String s : subtags) {
1532             buf.append(LanguageTag.SEP);
1533             buf.append(LanguageTag.canonicalizeExtension(s));
1534         }
1535 
1536         subtag = tag.getPrivateuse();
1537         if (subtag.length() > 0) {
1538             if (buf.length() > 0) {
1539                 buf.append(LanguageTag.SEP);
1540             }
1541             buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
1542             // preserve casing
1543             buf.append(subtag);
1544         }
1545 
1546         String langTag = buf.toString();
1547         synchronized (this) {
1548             if (languageTag == null) {
1549                 languageTag = langTag;
1550             }
1551         }
1552         return languageTag;
1553     }
1554 
1555     /**
1556      * Returns a locale for the specified IETF BCP 47 language tag string.
1557      *


1667      *
1668      * <p>For a list of all grandfathered tags, see the
1669      * IANA Language Subtag Registry (search for "Type: grandfathered").
1670      *
1671      * <p><b>Note</b>: there is no guarantee that <code>toLanguageTag</code>
1672      * and <code>forLanguageTag</code> will round-trip.
1673      *
1674      * @param languageTag the language tag
1675      * @return The locale that best represents the language tag.
1676      * @throws NullPointerException if <code>languageTag</code> is <code>null</code>
1677      * @see #toLanguageTag()
1678      * @see java.util.Locale.Builder#setLanguageTag(String)
1679      * @since 1.7
1680      */
1681     public static Locale forLanguageTag(String languageTag) {
1682         LanguageTag tag = LanguageTag.parse(languageTag, null);
1683         InternalLocaleBuilder bldr = new InternalLocaleBuilder();
1684         bldr.setLanguageTag(tag);
1685         BaseLocale base = bldr.getBaseLocale();
1686         LocaleExtensions exts = bldr.getLocaleExtensions();
1687         if (exts == null && base.getVariant().length() > 0) {
1688             exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(),
1689                                               base.getRegion(), base.getVariant());
1690         }
1691         return getInstance(base, exts);
1692     }
1693 
1694     /**
1695      * Returns a three-letter abbreviation of this locale's language.
1696      * If the language matches an ISO 639-1 two-letter code, the
1697      * corresponding ISO 639-2/T three-letter lowercase code is
1698      * returned.  The ISO 639-2 language codes can be found on-line,
1699      * see "Codes for the Representation of Names of Languages Part 2:
1700      * Alpha-3 Code".  If the locale specifies a three-letter
1701      * language, the language is returned as is.  If the locale does
1702      * not specify a language the empty string is returned.
1703      *
1704      * @return A three-letter abbreviation of this locale's language.
1705      * @exception MissingResourceException Throws MissingResourceException if
1706      * three-letter language abbreviation is not available for this locale.
1707      */


1900      * user.  If possible, the name will be localized for the default
1901      * {@link Locale.Category#DISPLAY DISPLAY} locale.  If the locale
1902      * doesn't specify a variant code, this function returns the empty string.
1903      *
1904      * @return The name of the display variant code appropriate to the locale.
1905      */
1906     public final String getDisplayVariant() {
1907         return getDisplayVariant(getDefault(Category.DISPLAY));
1908     }
1909 
1910     /**
1911      * Returns a name for the locale's variant code that is appropriate for display to the
1912      * user.  If possible, the name will be localized for inLocale.  If the locale
1913      * doesn't specify a variant code, this function returns the empty string.
1914      *
1915      * @param inLocale The locale for which to retrieve the display variant code.
1916      * @return The name of the display variant code appropriate to the given locale.
1917      * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1918      */
1919     public String getDisplayVariant(Locale inLocale) {
1920         if (baseLocale.getVariant().length() == 0)
1921             return "";
1922 
1923         LocaleResources lr = LocaleProviderAdapter
1924             .getResourceBundleBased()
1925             .getLocaleResources(inLocale);
1926 
1927         String names[] = getDisplayVariantArray(inLocale);
1928 
1929         // Get the localized patterns for formatting a list, and use
1930         // them to format the list.
1931         return formatList(names,
1932                           lr.getLocaleName("ListCompositionPattern"));
1933     }
1934 
1935     /**
1936      * Returns a name for the locale that is appropriate for display to the
1937      * user. This will be the values returned by getDisplayLanguage(),
1938      * getDisplayScript(), getDisplayCountry(), getDisplayVariant() and
1939      * optional <a href="./Locale.html#def_locale_extension">Unicode extensions</a>
1940      * assembled into a single string. The non-empty values are used in order, with


1981      * @return The name of the locale appropriate to display.
1982      * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1983      */
1984     public String getDisplayName(Locale inLocale) {
1985         LocaleResources lr =  LocaleProviderAdapter
1986             .getResourceBundleBased()
1987             .getLocaleResources(inLocale);
1988 
1989         String languageName = getDisplayLanguage(inLocale);
1990         String scriptName = getDisplayScript(inLocale);
1991         String countryName = getDisplayCountry(inLocale);
1992         String[] variantNames = getDisplayVariantArray(inLocale);
1993 
1994         // Get the localized patterns for formatting a display name.
1995         String displayNamePattern = lr.getLocaleName("DisplayNamePattern");
1996         String listCompositionPattern = lr.getLocaleName("ListCompositionPattern");
1997 
1998         // The display name consists of a main name, followed by qualifiers.
1999         // Typically, the format is "MainName (Qualifier, Qualifier)" but this
2000         // depends on what pattern is stored in the display locale.
2001         String   mainName       = null;
2002         String[] qualifierNames = null;
2003 
2004         // The main name is the language, or if there is no language, the script,
2005         // then if no script, the country. If there is no language/script/country
2006         // (an anomalous situation) then the display name is simply the variant's
2007         // display name.
2008         if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) {
2009             if (variantNames.length == 0) {
2010                 return "";
2011             } else {
2012                 return formatList(variantNames, listCompositionPattern);
2013             }
2014         }
2015         ArrayList<String> names = new ArrayList<>(4);
2016         if (languageName.length() != 0) {
2017             names.add(languageName);
2018         }
2019         if (scriptName.length() != 0) {
2020             names.add(scriptName);
2021         }
2022         if (countryName.length() != 0) {
2023             names.add(countryName);
2024         }
2025         if (variantNames.length != 0) {
2026             names.addAll(Arrays.asList(variantNames));
2027         }
2028 
2029         // add Unicode extensions
2030         if (localeExtensions != null) {
2031             localeExtensions.getUnicodeLocaleAttributes().stream()
2032                 .map(key -> getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY))
2033                 .forEach(names::add);
2034             localeExtensions.getUnicodeLocaleKeys().stream()
2035                 .map(key -> getDisplayKeyTypeExtensionString(key, lr, inLocale))
2036                 .forEach(names::add);
2037         }
2038 
2039         // The first one in the main name
2040         mainName = names.get(0);
2041 
2042         // Others are qualifiers


2292         fields.put("hashcode", -1); // place holder just for backward support
2293         out.writeFields();
2294     }
2295 
2296     /**
2297      * Deserializes this <code>Locale</code>.
2298      * @param in the <code>ObjectInputStream</code> to read
2299      * @throws IOException
2300      * @throws ClassNotFoundException
2301      * @throws IllformedLocaleException
2302      * @since 1.7
2303      */
2304     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
2305         ObjectInputStream.GetField fields = in.readFields();
2306         String language = (String)fields.get("language", "");
2307         String script = (String)fields.get("script", "");
2308         String country = (String)fields.get("country", "");
2309         String variant = (String)fields.get("variant", "");
2310         String extStr = (String)fields.get("extensions", "");
2311         baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant);
2312         if (extStr.length() > 0) {
2313             try {
2314                 InternalLocaleBuilder bldr = new InternalLocaleBuilder();
2315                 bldr.setExtensions(extStr);
2316                 localeExtensions = bldr.getLocaleExtensions();
2317             } catch (LocaleSyntaxException e) {
2318                 throw new IllformedLocaleException(e.getMessage());
2319             }
2320         } else {
2321             localeExtensions = null;
2322         }
2323     }
2324 
2325     /**
2326      * Returns a cached <code>Locale</code> instance equivalent to
2327      * the deserialized <code>Locale</code>. When serialized
2328      * language, country and variant fields read from the object data stream
2329      * are exactly "ja", "JP", "JP" or "th", "TH", "TH" and script/extensions
2330      * fields are empty, this method supplies <code>UNICODE_LOCALE_EXTENSION</code>
2331      * "ca"/"japanese" (calendar type is "japanese") or "nu"/"thai" (number script
2332      * type is "thai"). See <a href="Locale.html#special_cases_constructor">Special Cases</a>


2350         // codes have changed, but we always store the OLD code, for backward compatibility
2351         language = LocaleUtils.toLowerString(language).intern();
2352         if (language == "he") {
2353             return "iw";
2354         } else if (language == "yi") {
2355             return "ji";
2356         } else if (language == "id") {
2357             return "in";
2358         } else {
2359             return language;
2360         }
2361     }
2362 
2363     private static LocaleExtensions getCompatibilityExtensions(String language,
2364                                                                String script,
2365                                                                String country,
2366                                                                String variant) {
2367         LocaleExtensions extensions = null;
2368         // Special cases for backward compatibility support
2369         if (LocaleUtils.caseIgnoreMatch(language, "ja")
2370                 && script.length() == 0
2371                 && LocaleUtils.caseIgnoreMatch(country, "jp")
2372                 && "JP".equals(variant)) {
2373             // ja_JP_JP -> u-ca-japanese (calendar = japanese)
2374             extensions = LocaleExtensions.CALENDAR_JAPANESE;
2375         } else if (LocaleUtils.caseIgnoreMatch(language, "th")
2376                 && script.length() == 0
2377                 && LocaleUtils.caseIgnoreMatch(country, "th")
2378                 && "TH".equals(variant)) {
2379             // th_TH_TH -> u-nu-thai (numbersystem = thai)
2380             extensions = LocaleExtensions.NUMBER_THAI;
2381         }
2382         return extensions;
2383     }
2384 
2385     /**
2386      * Obtains a localized locale names from a LocaleNameProvider
2387      * implementation.
2388      */
2389     private static class LocaleNameGetter
2390         implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
2391         private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
2392 
2393         @Override
2394         public String getObject(LocaleNameProvider localeNameProvider,
2395                                 Locale locale,
2396                                 String key,


2789          * @see #setExtension(char, String)
2790          */
2791         public Builder clearExtensions() {
2792             localeBuilder.clearExtensions();
2793             return this;
2794         }
2795 
2796         /**
2797          * Returns an instance of <code>Locale</code> created from the fields set
2798          * on this builder.
2799          *
2800          * <p>This applies the conversions listed in {@link Locale#forLanguageTag}
2801          * when constructing a Locale. (Grandfathered tags are handled in
2802          * {@link #setLanguageTag}.)
2803          *
2804          * @return A Locale.
2805          */
2806         public Locale build() {
2807             BaseLocale baseloc = localeBuilder.getBaseLocale();
2808             LocaleExtensions extensions = localeBuilder.getLocaleExtensions();
2809             if (extensions == null && baseloc.getVariant().length() > 0) {
2810                 extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(),
2811                         baseloc.getRegion(), baseloc.getVariant());
2812             }
2813             return Locale.getInstance(baseloc, extensions);
2814         }
2815     }
2816 
2817     /**
2818      * This enum provides constants to select a filtering mode for locale
2819      * matching. Refer to <a href="http://tools.ietf.org/html/rfc4647">RFC 4647
2820      * Matching of Language Tags</a> for details.
2821      *
2822      * <p>As an example, think of two Language Priority Lists each of which
2823      * includes only one language range and a set of following language tags:
2824      *
2825      * <pre>
2826      *    de (German)
2827      *    de-DE (German, Germany)
2828      *    de-Deva (German, in Devanagari script)
2829      *    de-Deva-DE (German, in Devanagari script, Germany)




1379      * previous uses of <code>toString</code> that expected language, country, and variant
1380      * fields only.  To represent a Locale as a String for interchange purposes, use
1381      * {@link #toLanguageTag}.
1382      *
1383      * <p>Examples: <ul>
1384      * <li>{@code en}</li>
1385      * <li>{@code de_DE}</li>
1386      * <li>{@code _GB}</li>
1387      * <li>{@code en_US_WIN}</li>
1388      * <li>{@code de__POSIX}</li>
1389      * <li>{@code zh_CN_#Hans}</li>
1390      * <li>{@code zh_TW_#Hant_x-java}</li>
1391      * <li>{@code th_TH_TH_#u-nu-thai}</li></ul>
1392      *
1393      * @return A string representation of the Locale, for debugging.
1394      * @see #getDisplayName
1395      * @see #toLanguageTag
1396      */
1397     @Override
1398     public final String toString() {
1399         boolean l = !baseLocale.getLanguage().isEmpty();
1400         boolean s = !baseLocale.getScript().isEmpty();
1401         boolean r = !baseLocale.getRegion().isEmpty();
1402         boolean v = !baseLocale.getVariant().isEmpty();
1403         boolean e = localeExtensions != null && !localeExtensions.getID().isEmpty();
1404 
1405         StringBuilder result = new StringBuilder(baseLocale.getLanguage());
1406         if (r || (l && (v || s || e))) {
1407             result.append('_')
1408                 .append(baseLocale.getRegion()); // This may just append '_'
1409         }
1410         if (v && (l || r)) {
1411             result.append('_')
1412                 .append(baseLocale.getVariant());
1413         }
1414 
1415         if (s && (l || r)) {
1416             result.append("_#")
1417                 .append(baseLocale.getScript());
1418         }
1419 
1420         if (e && (l || r)) {
1421             result.append('_');
1422             if (!s) {
1423                 result.append('#');


1487      * <pre>
1488      *   new Locale("xx", "YY").toLanguageTag();</pre>
1489      *
1490      * will return "xx-YY", but the language subtag "xx" and the
1491      * region subtag "YY" are invalid because they are not registered
1492      * in the IANA Language Subtag Registry.
1493      *
1494      * @return a BCP47 language tag representing the locale
1495      * @see #forLanguageTag(String)
1496      * @since 1.7
1497      */
1498     public String toLanguageTag() {
1499         if (languageTag != null) {
1500             return languageTag;
1501         }
1502 
1503         LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
1504         StringBuilder buf = new StringBuilder();
1505 
1506         String subtag = tag.getLanguage();
1507         if (!subtag.isEmpty()) {
1508             buf.append(LanguageTag.canonicalizeLanguage(subtag));
1509         }
1510 
1511         subtag = tag.getScript();
1512         if (!subtag.isEmpty()) {
1513             buf.append(LanguageTag.SEP);
1514             buf.append(LanguageTag.canonicalizeScript(subtag));
1515         }
1516 
1517         subtag = tag.getRegion();
1518         if (!subtag.isEmpty()) {
1519             buf.append(LanguageTag.SEP);
1520             buf.append(LanguageTag.canonicalizeRegion(subtag));
1521         }
1522 
1523         List<String>subtags = tag.getVariants();
1524         for (String s : subtags) {
1525             buf.append(LanguageTag.SEP);
1526             // preserve casing
1527             buf.append(s);
1528         }
1529 
1530         subtags = tag.getExtensions();
1531         for (String s : subtags) {
1532             buf.append(LanguageTag.SEP);
1533             buf.append(LanguageTag.canonicalizeExtension(s));
1534         }
1535 
1536         subtag = tag.getPrivateuse();
1537         if (!subtag.isEmpty()) {
1538             if (buf.length() > 0) {
1539                 buf.append(LanguageTag.SEP);
1540             }
1541             buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
1542             // preserve casing
1543             buf.append(subtag);
1544         }
1545 
1546         String langTag = buf.toString();
1547         synchronized (this) {
1548             if (languageTag == null) {
1549                 languageTag = langTag;
1550             }
1551         }
1552         return languageTag;
1553     }
1554 
1555     /**
1556      * Returns a locale for the specified IETF BCP 47 language tag string.
1557      *


1667      *
1668      * <p>For a list of all grandfathered tags, see the
1669      * IANA Language Subtag Registry (search for "Type: grandfathered").
1670      *
1671      * <p><b>Note</b>: there is no guarantee that <code>toLanguageTag</code>
1672      * and <code>forLanguageTag</code> will round-trip.
1673      *
1674      * @param languageTag the language tag
1675      * @return The locale that best represents the language tag.
1676      * @throws NullPointerException if <code>languageTag</code> is <code>null</code>
1677      * @see #toLanguageTag()
1678      * @see java.util.Locale.Builder#setLanguageTag(String)
1679      * @since 1.7
1680      */
1681     public static Locale forLanguageTag(String languageTag) {
1682         LanguageTag tag = LanguageTag.parse(languageTag, null);
1683         InternalLocaleBuilder bldr = new InternalLocaleBuilder();
1684         bldr.setLanguageTag(tag);
1685         BaseLocale base = bldr.getBaseLocale();
1686         LocaleExtensions exts = bldr.getLocaleExtensions();
1687         if (exts == null && !base.getVariant().isEmpty()) {
1688             exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(),
1689                                               base.getRegion(), base.getVariant());
1690         }
1691         return getInstance(base, exts);
1692     }
1693 
1694     /**
1695      * Returns a three-letter abbreviation of this locale's language.
1696      * If the language matches an ISO 639-1 two-letter code, the
1697      * corresponding ISO 639-2/T three-letter lowercase code is
1698      * returned.  The ISO 639-2 language codes can be found on-line,
1699      * see "Codes for the Representation of Names of Languages Part 2:
1700      * Alpha-3 Code".  If the locale specifies a three-letter
1701      * language, the language is returned as is.  If the locale does
1702      * not specify a language the empty string is returned.
1703      *
1704      * @return A three-letter abbreviation of this locale's language.
1705      * @exception MissingResourceException Throws MissingResourceException if
1706      * three-letter language abbreviation is not available for this locale.
1707      */


1900      * user.  If possible, the name will be localized for the default
1901      * {@link Locale.Category#DISPLAY DISPLAY} locale.  If the locale
1902      * doesn't specify a variant code, this function returns the empty string.
1903      *
1904      * @return The name of the display variant code appropriate to the locale.
1905      */
1906     public final String getDisplayVariant() {
1907         return getDisplayVariant(getDefault(Category.DISPLAY));
1908     }
1909 
1910     /**
1911      * Returns a name for the locale's variant code that is appropriate for display to the
1912      * user.  If possible, the name will be localized for inLocale.  If the locale
1913      * doesn't specify a variant code, this function returns the empty string.
1914      *
1915      * @param inLocale The locale for which to retrieve the display variant code.
1916      * @return The name of the display variant code appropriate to the given locale.
1917      * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1918      */
1919     public String getDisplayVariant(Locale inLocale) {
1920         if (baseLocale.getVariant().isEmpty())
1921             return "";
1922 
1923         LocaleResources lr = LocaleProviderAdapter
1924             .getResourceBundleBased()
1925             .getLocaleResources(inLocale);
1926 
1927         String names[] = getDisplayVariantArray(inLocale);
1928 
1929         // Get the localized patterns for formatting a list, and use
1930         // them to format the list.
1931         return formatList(names,
1932                           lr.getLocaleName("ListCompositionPattern"));
1933     }
1934 
1935     /**
1936      * Returns a name for the locale that is appropriate for display to the
1937      * user. This will be the values returned by getDisplayLanguage(),
1938      * getDisplayScript(), getDisplayCountry(), getDisplayVariant() and
1939      * optional <a href="./Locale.html#def_locale_extension">Unicode extensions</a>
1940      * assembled into a single string. The non-empty values are used in order, with


1981      * @return The name of the locale appropriate to display.
1982      * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1983      */
1984     public String getDisplayName(Locale inLocale) {
1985         LocaleResources lr =  LocaleProviderAdapter
1986             .getResourceBundleBased()
1987             .getLocaleResources(inLocale);
1988 
1989         String languageName = getDisplayLanguage(inLocale);
1990         String scriptName = getDisplayScript(inLocale);
1991         String countryName = getDisplayCountry(inLocale);
1992         String[] variantNames = getDisplayVariantArray(inLocale);
1993 
1994         // Get the localized patterns for formatting a display name.
1995         String displayNamePattern = lr.getLocaleName("DisplayNamePattern");
1996         String listCompositionPattern = lr.getLocaleName("ListCompositionPattern");
1997 
1998         // The display name consists of a main name, followed by qualifiers.
1999         // Typically, the format is "MainName (Qualifier, Qualifier)" but this
2000         // depends on what pattern is stored in the display locale.
2001         String   mainName;
2002         String[] qualifierNames;
2003 
2004         // The main name is the language, or if there is no language, the script,
2005         // then if no script, the country. If there is no language/script/country
2006         // (an anomalous situation) then the display name is simply the variant's
2007         // display name.
2008         if (languageName.isEmpty() && scriptName.isEmpty() && countryName.isEmpty()) {
2009             if (variantNames.length == 0) {
2010                 return "";
2011             } else {
2012                 return formatList(variantNames, listCompositionPattern);
2013             }
2014         }
2015         ArrayList<String> names = new ArrayList<>(4);
2016         if (!languageName.isEmpty()) {
2017             names.add(languageName);
2018         }
2019         if (!scriptName.isEmpty()) {
2020             names.add(scriptName);
2021         }
2022         if (!countryName.isEmpty()) {
2023             names.add(countryName);
2024         }
2025         if (variantNames.length != 0) {
2026             names.addAll(Arrays.asList(variantNames));
2027         }
2028 
2029         // add Unicode extensions
2030         if (localeExtensions != null) {
2031             localeExtensions.getUnicodeLocaleAttributes().stream()
2032                 .map(key -> getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY))
2033                 .forEach(names::add);
2034             localeExtensions.getUnicodeLocaleKeys().stream()
2035                 .map(key -> getDisplayKeyTypeExtensionString(key, lr, inLocale))
2036                 .forEach(names::add);
2037         }
2038 
2039         // The first one in the main name
2040         mainName = names.get(0);
2041 
2042         // Others are qualifiers


2292         fields.put("hashcode", -1); // place holder just for backward support
2293         out.writeFields();
2294     }
2295 
2296     /**
2297      * Deserializes this <code>Locale</code>.
2298      * @param in the <code>ObjectInputStream</code> to read
2299      * @throws IOException
2300      * @throws ClassNotFoundException
2301      * @throws IllformedLocaleException
2302      * @since 1.7
2303      */
2304     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
2305         ObjectInputStream.GetField fields = in.readFields();
2306         String language = (String)fields.get("language", "");
2307         String script = (String)fields.get("script", "");
2308         String country = (String)fields.get("country", "");
2309         String variant = (String)fields.get("variant", "");
2310         String extStr = (String)fields.get("extensions", "");
2311         baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant);
2312         if (!extStr.isEmpty()) {
2313             try {
2314                 InternalLocaleBuilder bldr = new InternalLocaleBuilder();
2315                 bldr.setExtensions(extStr);
2316                 localeExtensions = bldr.getLocaleExtensions();
2317             } catch (LocaleSyntaxException e) {
2318                 throw new IllformedLocaleException(e.getMessage());
2319             }
2320         } else {
2321             localeExtensions = null;
2322         }
2323     }
2324 
2325     /**
2326      * Returns a cached <code>Locale</code> instance equivalent to
2327      * the deserialized <code>Locale</code>. When serialized
2328      * language, country and variant fields read from the object data stream
2329      * are exactly "ja", "JP", "JP" or "th", "TH", "TH" and script/extensions
2330      * fields are empty, this method supplies <code>UNICODE_LOCALE_EXTENSION</code>
2331      * "ca"/"japanese" (calendar type is "japanese") or "nu"/"thai" (number script
2332      * type is "thai"). See <a href="Locale.html#special_cases_constructor">Special Cases</a>


2350         // codes have changed, but we always store the OLD code, for backward compatibility
2351         language = LocaleUtils.toLowerString(language).intern();
2352         if (language == "he") {
2353             return "iw";
2354         } else if (language == "yi") {
2355             return "ji";
2356         } else if (language == "id") {
2357             return "in";
2358         } else {
2359             return language;
2360         }
2361     }
2362 
2363     private static LocaleExtensions getCompatibilityExtensions(String language,
2364                                                                String script,
2365                                                                String country,
2366                                                                String variant) {
2367         LocaleExtensions extensions = null;
2368         // Special cases for backward compatibility support
2369         if (LocaleUtils.caseIgnoreMatch(language, "ja")
2370                 && script.isEmpty()
2371                 && LocaleUtils.caseIgnoreMatch(country, "jp")
2372                 && "JP".equals(variant)) {
2373             // ja_JP_JP -> u-ca-japanese (calendar = japanese)
2374             extensions = LocaleExtensions.CALENDAR_JAPANESE;
2375         } else if (LocaleUtils.caseIgnoreMatch(language, "th")
2376                 && script.isEmpty()
2377                 && LocaleUtils.caseIgnoreMatch(country, "th")
2378                 && "TH".equals(variant)) {
2379             // th_TH_TH -> u-nu-thai (numbersystem = thai)
2380             extensions = LocaleExtensions.NUMBER_THAI;
2381         }
2382         return extensions;
2383     }
2384 
2385     /**
2386      * Obtains a localized locale names from a LocaleNameProvider
2387      * implementation.
2388      */
2389     private static class LocaleNameGetter
2390         implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
2391         private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
2392 
2393         @Override
2394         public String getObject(LocaleNameProvider localeNameProvider,
2395                                 Locale locale,
2396                                 String key,


2789          * @see #setExtension(char, String)
2790          */
2791         public Builder clearExtensions() {
2792             localeBuilder.clearExtensions();
2793             return this;
2794         }
2795 
2796         /**
2797          * Returns an instance of <code>Locale</code> created from the fields set
2798          * on this builder.
2799          *
2800          * <p>This applies the conversions listed in {@link Locale#forLanguageTag}
2801          * when constructing a Locale. (Grandfathered tags are handled in
2802          * {@link #setLanguageTag}.)
2803          *
2804          * @return A Locale.
2805          */
2806         public Locale build() {
2807             BaseLocale baseloc = localeBuilder.getBaseLocale();
2808             LocaleExtensions extensions = localeBuilder.getLocaleExtensions();
2809             if (extensions == null && !baseloc.getVariant().isEmpty()) {
2810                 extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(),
2811                         baseloc.getRegion(), baseloc.getVariant());
2812             }
2813             return Locale.getInstance(baseloc, extensions);
2814         }
2815     }
2816 
2817     /**
2818      * This enum provides constants to select a filtering mode for locale
2819      * matching. Refer to <a href="http://tools.ietf.org/html/rfc4647">RFC 4647
2820      * Matching of Language Tags</a> for details.
2821      *
2822      * <p>As an example, think of two Language Priority Lists each of which
2823      * includes only one language range and a set of following language tags:
2824      *
2825      * <pre>
2826      *    de (German)
2827      *    de-DE (German, Germany)
2828      *    de-Deva (German, in Devanagari script)
2829      *    de-Deva-DE (German, in Devanagari script, Germany)


< prev index next >