编码中通常遇到金额以及小数点精度计算,为避免精度丢失,将double类型转换为BigDecimal再进行相关计算,或者使用DecimalFormat进行转换。
BigDecimal是Java提供的一个不变的、任意精度的有符号十进制数对象,继承自Number类。BigDecimal类提供了算术操作,操作规模,四舍五入,比较,哈希和格式转换。
public BigDecimal(double val)
public BigDecimal(int val)
public BigDecimal(String val)
public BigDecimal add(BigDecimal augend)
public BigDecimal subtract(BigDecimal subtrahend)
public BigDecimal multiply(BigDecimal multiplicand)
public BigDecimal divide(BigDecimal divisor)
public BigDecimal remainder(BigDecimal divisor)
public BigDecimal[] divideAndRemainder(BigDecimal divisor)
public BigDecimal setScale(int newScale) {
return setScale(newScale, RoundingMode.UNNECESSARY);
}
// ......
public BigDecimal setScale(int newScale, int roundingMode) {
return setScale(newScale, RoundingMode.valueOf(roundingMode));
}
/**
* 加法运算。
*
* @param amount1 被加数
* @param amount2 加数
* @return 两个参数的和
*/
public static double add(double amount1, double amount2) {
BigDecimal mDecimal1 = new BigDecimal(Double.toString(amount1));
BigDecimal mDecimal2 = new BigDecimal(Double.toString(amount2));
return mDecimal1.add(mDecimal2).doubleValue();
}
/**
* 减法运算。
*
* @param amount1 被减数
* @param amount2 减数
* @return 两个参数的差
*/
public static double subtraction(double amount1, double amount2) {
BigDecimal mDecimal1 = new BigDecimal(Double.toString(amount1));
BigDecimal mDecimal2 = new BigDecimal(Double.toString(amount2));
return mDecimal1.subtract(mDecimal2).doubleValue();
}
/**
* 乘法运算。
*
* @param amount1 被乘数
* @param amount2 乘数
* @return 两个参数的积
*/
public static double multiplication(double amount1, double amount2) {
BigDecimal mDecimal1 = new BigDecimal(Double.toString(amount1));
BigDecimal mDecimal2 = new BigDecimal(Double.toString(amount2));
return mDecimal1.multiply(mDecimal2).doubleValue();
}
/**
* 除法运算。
* MathContext.DECIMAL128其精度设置与Decimal128格式,34位数字和 [HALF_EVEN]的舍入模式一样。
* divide()方法默认为MathContext.UNLIMITED无限取值,不做限制陷入死循环会抛出ArithmeticException(计算溢出)异常。
*
* @param amount1 被除数
* @param amount2 除数
* @return 两个参数的商
*/
public static double divisionOperation(double amount1, double amount2) {
BigDecimal mDecimal1 = new BigDecimal(Double.toString(amount1));
BigDecimal mDecimal2 = new BigDecimal(Double.toString(amount2));
return mDecimal1.divide(mDecimal2, MathContext.DECIMAL128).doubleValue();
}
DecimalFormat是一个NumberFormat的子类的格式小数。它有各种各样的功能设计使它可以解析和格式化数字在任何地区,包括支持西方,阿拉伯语和印度语的数字。它还支持不同类型的数据,包括整数(123),定点数(123.4),科学记数法(1.23 e4)百分比(12%)和货币数量(123美元)等。
public DecimalFormat() {
Locale def = Locale.getDefault(Locale.Category.FORMAT);
// try to get the pattern from the cache
String pattern = cachedLocaleData.get(def);
if (pattern == null) { /* cache miss */
// Get the pattern for the default locale.
pattern = LocaleData.get(def).numberPattern;
/* update cache */
cachedLocaleData.putIfAbsent(def, pattern);
}
this.symbols = new DecimalFormatSymbols(def);
init(pattern);
}
public DecimalFormat(String pattern)
public DecimalFormat(String pattern, DecimalFormatSymbols symbols)
public void applyPattern(String pattern)
public final String format(double number)
public void setCurrency(Currency currency)
public void setMaximumFractionDigits(int newValue)
public void setMinimumFractionDigits(int newValue)
public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols)
public void setNegativePrefix(String newValue)
public void setPositiveSuffix(String newValue)
public void setGroupingUsed(boolean newValue)
public void setGroupingSize(int newValue)
/**
* 格式化保留两位小数,默认四舍五入
*
* @param amount
* @return
*/
public static String formatTwoDecimals(double amount) {
DecimalFormat mFormat = new DecimalFormat();
// 设置区域
mFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.CHINA));
// 设置格式化保留两位小数
mFormat.applyPattern("#0.00");
return mFormat.format(amount);
}
/**
* 格式化保留两位小数,只舍不入
*
* @param amount
* @return
*/
public static String formatTwoDecimalsDown(double amount) {
DecimalFormat mFormat = new DecimalFormat();
// 设置区域
mFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.CHINA));
// 设置格式化保留两位小数
mFormat.applyPattern("#0.00");
// 设置只舍不入
mFormat.setRoundingMode(RoundingMode.DOWN);
return mFormat.format(amount);
}
/**
* 保留有效数,最多保留两位
*
* @return
*/
public static String formatTwoEffectiveNumber(double amount) {
DecimalFormat mFormat = new DecimalFormat();
// 设置区域
mFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.CHINA));
// 设置保留两位有效数
mFormat.applyPattern("#0.##");
// 设置只舍不入
mFormat.setRoundingMode(RoundingMode.DOWN);
return mFormat.format(amount);
}
/**
* 金额3位数分组,如10000——>10,000
*
* @param amount
* @return
*/
public static String formatAmountGrouping(double amount) {
DecimalFormat mFormat = new DecimalFormat();
// 设置区域
mFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.CHINA));
// 设置使用逗号“,”将金额分隔开
mFormat.setGroupingUsed(true);
// 设置分隔位数
mFormat.setGroupingSize(3);
return mFormat.format(amount);
}
符号 | 位置 | 本地化 | 含义 |
---|---|---|---|
0 | 数字 | 是 | 阿拉伯数字 |
# | 数字 | 是 | 阿拉伯数字,如果不存在则显示为空 |
. | 数字 | 是 | 小数分隔符或货币小数分隔符 |
- | 数字 | 是 | 缺省负数前缀 |
, | 数字 | 是 | 分组分隔符 |
E | 数字 | 是 | 分隔科学计数法中的尾数和指数。在前缀或后缀中无需加引号 |
% | 前缀或后缀 | 是 | 乘以100和作为百分比显示 |
/u2030 | 前缀或后缀 | 是 | 乘以1000并显示为千分数 |
源码如下:
public enum RoundingMode {
/**
* 向上进位,如:
* 2.56计算后保留一位小数则为2.6
* 1.1保留整数则为2
* -2.5保留整数为-3
*/
UP(BigDecimal.ROUND_UP),
/**
* 舍入模式为零。
*/
DOWN(BigDecimal.ROUND_DOWN),
/**
* 舍入模式正无穷。
*/
CEILING(BigDecimal.ROUND_CEILING),
/**
* 舍入模式向负无穷。
*/
FLOOR(BigDecimal.ROUND_FLOOR),
/**
* 舍入模式向“最近邻”轮除非邻居都是等距的,在这种情况下一轮。
*/
HALF_UP(BigDecimal.ROUND_HALF_UP),
/**
* 舍入模式向“最近邻”轮除非邻居都是等距的,在这种情况下一轮下来。
*/
HALF_DOWN(BigDecimal.ROUND_HALF_DOWN),
/**
* 舍入模式向“最近邻”轮除非邻居都是等距的,在这种情况下,甚至向邻居。
*/
HALF_EVEN(BigDecimal.ROUND_HALF_EVEN),
/**
* 舍入模式断言请求的操作有一个确切的结果,因此不需要舍入。
*/
UNNECESSARY(BigDecimal.ROUND_UNNECESSARY);
private final int bigDecimalRM;
RoundingMode(int rm) {
bigDecimalRM = rm;
}
/**
* 返回与指定名称这种类型的枚举常量。
* 字符串必须匹配完全一个标识符用于声明一个枚举常数在这个类型。 (多余的空格字符是不允许的。) 参数
*/
public static RoundingMode valueOf(int mode) {
switch (mode) {
case BigDecimal.ROUND_CEILING:
return CEILING;
case BigDecimal.ROUND_DOWN:
return DOWN;
case BigDecimal.ROUND_FLOOR:
return FLOOR;
case BigDecimal.ROUND_HALF_DOWN:
return HALF_DOWN;
case BigDecimal.ROUND_HALF_EVEN:
return HALF_EVEN;
case BigDecimal.ROUND_HALF_UP:
return HALF_UP;
case BigDecimal.ROUND_UNNECESSARY:
return UNNECESSARY;
case BigDecimal.ROUND_UP:
return UP;
default:
throw new IllegalArgumentException("Invalid rounding mode");
}
}
}