1、背景
在日常开发中有时会使用到float或double数据类型,然而在前端接收到数据时发现数据为科学记数法,此时不能满足业务显示直观的需求。为什么float和double会变成科学记数法格式呢?什么情况下会自动转换?
2、思考
带着上面的两个问题,我们一起撸撸源码吧。
(1) Float类对数据赋值和显示时会调用toString()方法:
public static String toString(float f) {
return FloatingDecimal.toJavaFormatString(f);
}
(2) 在FloatingDecimal类中调用toJavaFormatString()时,需要调用转换器:
public static String toJavaFormatString(float var0) {
return getBinaryToASCIIConverter(var0).toJavaFormatString();
}
(3) 其中BinaryToASCIIConverter接口的toJavaFormatString()方法实现如下:
public String toJavaFormatString() {
int var1 = this.getChars(this.buffer);
return new String(this.buffer, 0, var1);
}
(4) 在getChars()方法中,float和double完成了科学记数法的变形
if (this.decExponent > 0 && this.decExponent < 8) {
var3 = Math.min(this.nDigits, this.decExponent);
System.arraycopy(this.digits, this.firstDigitIndex, var1, var2, var3);
var5 = var2 + var3;
if (var3 < this.decExponent) {
var3 = this.decExponent - var3;
Arrays.fill(var1, var5, var5 + var3, '0');
var5 += var3;
var1[var5++] = '.';
var1[var5++] = '0';
} else {
var1[var5++] = '.';
if (var3 < this.nDigits) {
int var4 = this.nDigits - var3;
System.arraycopy(this.digits, this.firstDigitIndex + var3, var1, var5, var4);
var5 += var4;
} else {
var1[var5++] = '0';
}
}
} else if (this.decExponent <= 0 && this.decExponent > -3) {
var5 = var2 + 1;
var1[var2] = '0';
var1[var5++] = '.';
if (this.decExponent != 0) {
Arrays.fill(var1, var5, var5 - this.decExponent, '0');
var5 -= this.decExponent;
}
System.arraycopy(this.digits, this.firstDigitIndex, var1, var5, this.nDigits);
var5 += this.nDigits;
} else {
var5 = var2 + 1;
var1[var2] = this.digits[this.firstDigitIndex];
var1[var5++] = '.';
if (this.nDigits > 1) {
System.arraycopy(this.digits, this.firstDigitIndex + 1, var1, var5, this.nDigits - 1);
var5 += this.nDigits - 1;
} else {
var1[var5++] = '0';
}
var1[var5++] = 'E';
if (this.decExponent <= 0) {
var1[var5++] = '-';
var3 = -this.decExponent + 1;
} else {
var3 = this.decExponent - 1;
}
if (var3 <= 9) {
var1[var5++] = (char)(var3 + 48);
} else if (var3 <= 99) {
var1[var5++] = (char)(var3 / 10 + 48);
var1[var5++] = (char)(var3 % 10 + 48);
} else {
var1[var5++] = (char)(var3 / 100 + 48);
var3 %= 100;
var1[var5++] = (char)(var3 / 10 + 48);
var1[var5++] = (char)(var3 % 10 + 48);
}
}
在此部分代码中,分为三个大部分进行了转换:小数点前的位数大于0位但小于8位,数值为小于1且小数点紧跟的0小于3个,小数点前位数大于等于8位或纯小数的小数点后的0大于等于3。
简而言之,当数据为12345678或者0.0001222类型时,float或double数据会自动转换为科学记数法格式。
3、解决方法
(1) 数据采用BigDecimal格式
(2) NumberFormat
public static void main(String[] args) {
double d = 123456789.128d;
String s1 = big(d);
String s2 = big2(d);
System.out.println(d);
System.out.println(s1);
System.out.println(s2);
}
// 方法一:NumberFormat
private static String big(double d) {
NumberFormat nf = NumberFormat.getInstance();
// 是否以逗号隔开, 默认true以逗号隔开,如[123,456,789.128]
nf.setGroupingUsed(false);
// 结果未做任何处理
return nf.format(d);
}
//方法二: BigDecimal
private static String big2(double d) {
BigDecimal d1 = new BigDecimal(Double.toString(d));
BigDecimal d2 = new BigDecimal(Integer.toString(1));
// 四舍五入,保留2位小数
return d1.divide(d2,2,BigDecimal.ROUND_HALF_UP).toString();
}