Java 11中如何使用不支持的Locale(如ar-US)通过String.format()输出数字?
问题背景
你遇到的这个情况确实是Java 9之后本地化系统的变更导致的:Java 8默认使用JRE自带的本地化数据提供者,而Java 9及以后(包括Java 11)默认切换成了CLDR(Unicode通用区域数据仓库)作为本地化数据源。
在Java 8中,当使用ar-US这种“语言-地区”不匹配的非标准Locale时,系统会优先适配地区(US)的格式习惯,所以输出的是西方阿拉伯数字120;但CLDR的逻辑不同,它会优先遵循语言(ar,阿拉伯语)的默认数字系统,所以会输出东阿拉伯数字١٢٠。而且ar-US本身并不在Java 11官方支持的标准Locale列表里,这也加剧了这种差异。
解决办法
根据你的需求(要符合美国的数字格式习惯),这里有几种可行的方案:
1. 手动指定数字格式(推荐)
如果需要在保留ar-US语言环境的同时,强制使用美国风格的数字格式,可以用NumberFormat结合DecimalFormatSymbols来定制:
Locale locale = Locale.forLanguageTag("ar-US"); // 获取该Locale的数字格式化实例 NumberFormat numberFormat = NumberFormat.getInstance(locale); if (numberFormat instanceof DecimalFormat) { DecimalFormat decimalFormat = (DecimalFormat) numberFormat; // 设置美国的数字符号(西方阿拉伯数字) decimalFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US)); } // 输出结果:Output: 120 System.out.println(String.format(locale, "Output: %s", numberFormat.format(120)));
2. 切换回旧的本地化数据提供者
如果希望整个应用都沿用Java 8的Locale处理逻辑,可以在启动JVM时添加系统参数:
-Djava.locale.providers=COMPAT,SPI
这个参数会让Java优先使用兼容旧JRE的本地化数据(COMPAT就是原来的JRE提供者),这样String.format(locale, "Output: %d", 120)就会和Java 8一样输出120。不过这是全局设置,会影响所有本地化相关的功能,需要评估后使用。
3. 使用标准Locale替代
如果业务允许,直接使用符合需求的标准Locale会更稳妥:比如如果需要美国格式,直接用Locale.US;如果需要阿拉伯语且对应支持的地区(如阿联酋ar-AE),就用标准的语言-地区组合,避免非标准Locale带来的兼容性问题。
内容的提问来源于stack exchange,提问作者wittich

