前言
调试软件bug的过程中发现通过DecimalFormat.format()方法返回的字符串无法通过new BigDecimal()解析,在产品环境和开发环境之间来来回回加打印测试最后定位到是Windows系统下的Locale变化导致的。
问题描述
DecimalFormat decimalFormatter = new DecimalFormat("0.0");
String decimalStr = decimalFormatter.format("0.0");
上述代码在开发环境(Windows中文版)中执行结果为0.0 但在产品运行环境(Windows英文版)中执行结果为0,0,该行为导致了在使用该Formatter格式化后的字符串(含逗号的)无法直接通过new BigDecimal转化为数值使用。
Locale
A Locale object represents a specific geographical, political, or cultural region. An operation that requires a Locale to perform its task is called locale-sensitive and uses the Locale to tailor information for the user. For example, displaying a number is a locale-sensitive operation— the number should be formatted according to the customs and conventions of the user's native country, region, or culture.
在Java中,Locale类用来区分一些地域敏感的信息,例如字符集,国家编码,数字的格式等信息。而Locale的值在默认情况下由JVM在启动时检测系统环境获取,所以在不同的环境中也就会有不同的Locale值,这在开发环境和产品环境就可能造成困扰。
解决方法
既然运行结果的差异是由Locale导致的,所以在编码过程中需要屏蔽掉其带来的数字格式化时的差异。
public static void printDiffernece(Locale local){
NumberFormat nf = NumberFormat.getNumberInstance(local);
DecimalFormat df = (DecimalFormat)nf;
df.applyPattern("###,###.###");
String output = df.format(123456.789);
System.out.println("###,###.### " + output + " " + local.toString());
}
/*
JDK 1.8_131_32运行结果如下
pattern value locale
###,###.### 123,456.789 Locale.US
###,###.### 123.456,789 Locale.GERMANY
###,###.### 123?456,789 Locale.FRANCE
*/
可以看到在不同的Locale下,使用相同的格式和数值,格式化后的结果是不一样的,而这就是问题的所在。
通过在代码中统一使用Locale.CHINA起到屏蔽JVM使用自动检测到的Locale的效果,达到结果的一致性。
DecimalFormat decimalFormatter = (DecimalFormat) NumberFormat.getInstance(Locale.CHINA);
decimalFormatter.applyPattern("0.0");
以后在编码需要格式化Number的时候,需要将国际化也考虑进来。