今天发现, 当我们有一个Double类型的变量, 想把它转换成BigDecimal进行计算时,不能用new BigDecimal(double), 而是应该用BigDecimal.valueOf(double), 前者返回的数值不精确。
例如:
new BigDecimal(10.0).multiply(new BigDecimal(0.15))
会得到1.49, 而
BigDecimal.valueOf(10.0).multiply(BigDecimal.valueOf(0.15))
会得到1.50。
额外说一点,BigDecimal.valueOf(double)是这样的逻辑:
return new BigDecimal(Double.toString(val));
先转成String, 再new这个对象.
而MyBatis在转换BigDecimal时用到的BigDecimalTypeHandler是这样的:
@Override
public BigDecimal getNullableResult(ResultSet rs, String columnName)
throws SQLException {
return rs.getBigDecimal(columnName);
}
public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
if (!this.isBinaryEncoded) {
String stringVal = this.getString(columnIndex);
if (stringVal != null) {
BigDecimal val;
if (stringVal.length() == 0) {
val = new BigDecimal(this.convertToZeroLiteralStringWithEmptyCheck());
return val;
} else {
try {
val = new BigDecimal(stringVal);
return val;
} catch (NumberFormatException var5) {
throw SQLError.createSQLException(Messages.getString("ResultSet.Bad_format_for_BigDecimal", new Object[]{stringVal, columnIndex}), "S1009", this.getExceptionInterceptor());
}
}
} else {
return null;
}
} else {
return this.getNativeBigDecimal(columnIndex);
}
}
调用的是this.getString() 和this.convertToZeroLiteralStringWithEmptyCheck(), 先得到列的String值再new BigDecimal(), 所以MyBatis中可以放心使用BigDecimal不会出现误差。