Java/Android中BigDecimal的相关操作
在Java/Android中,BigDecimal 用于高精度的十进制运算。以下是详细的转换和操作方法:
1. 创建和初始化
基本创建方式
import java.math.BigDecimal;
import java.math.RoundingMode;// 1. 使用字符串创建(推荐,避免精度问题)
BigDecimal bd1 = new BigDecimal("123.456");
BigDecimal bd2 = new BigDecimal("100.00");// 2. 使用double创建(可能有不精确问题)
BigDecimal bd3 = new BigDecimal(123.456);// 3. 使用valueOf方法(内部会处理double的精度问题)
BigDecimal bd4 = BigDecimal.valueOf(123.456);
BigDecimal bd5 = BigDecimal.valueOf(100);// 4. 使用整数创建
BigDecimal bd6 = new BigDecimal(100);
BigDecimal bd7 = BigDecimal.valueOf(100L);// 5. 常用常量
BigDecimal zero = BigDecimal.ZERO;
BigDecimal one = BigDecimal.ONE;
BigDecimal ten = BigDecimal.TEN;
2. 基本算术运算
四则运算
BigDecimal a = new BigDecimal("10.50");
BigDecimal b = new BigDecimal("3.20");// 加法
BigDecimal sum = a.add(b); // 13.70// 减法
BigDecimal difference = a.subtract(b); // 7.30// 乘法
BigDecimal product = a.multiply(b); // 33.600// 除法(需要指定精度和舍入模式)
BigDecimal quotient = a.divide(b, 2, RoundingMode.HALF_UP); // 3.28// 取余
BigDecimal remainder = a.remainder(b); // 0.90
复杂运算示例
public class BigDecimalOperations {public static void main(String[] args) {BigDecimal price = new BigDecimal("99.99");BigDecimal quantity = new BigDecimal("3");BigDecimal taxRate = new BigDecimal("0.08"); // 8%// 计算总金额BigDecimal subtotal = price.multiply(quantity);// 计算税费BigDecimal tax = subtotal.multiply(taxRate).setScale(2, RoundingMode.HALF_UP);// 计算最终金额BigDecimal total = subtotal.add(tax);System.out.println("小计: $" + subtotal); // $299.97System.out.println("税费: $" + tax); // $24.00System.out.println("总计: $" + total); // $323.97}
}
3. 精度控制和舍入
设置精度和舍入模式
BigDecimal number = new BigDecimal("123.456789");// 设置小数位数
BigDecimal scaled1 = number.setScale(2, RoundingMode.HALF_UP); // 123.46
BigDecimal scaled2 = number.setScale(4, RoundingMode.FLOOR); // 123.4567// 除法时的精度控制
BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");// 指定小数位数和舍入模式
BigDecimal result1 = a.divide(b, 4, RoundingMode.HALF_UP); // 3.3333
BigDecimal result2 = a.divide(b, 2, RoundingMode.CEILING); // 3.34
舍入模式详解
BigDecimal number = new BigDecimal("123.456");// 常用舍入模式
BigDecimal halfUp = number.setScale(2, RoundingMode.HALF_UP); // 123.46
BigDecimal halfDown = number.setScale(2, RoundingMode.HALF_DOWN); // 123.46
BigDecimal halfEven = number.setScale(2, RoundingMode.HALF_EVEN); // 123.46
BigDecimal ceiling = number.setScale(2, RoundingMode.CEILING); // 123.46
BigDecimal floor = number.setScale(2, RoundingMode.FLOOR); // 123.45
BigDecimal up = number.setScale(2, RoundingMode.UP); // 123.46
BigDecimal down = number.setScale(2, RoundingMode.DOWN); // 123.45
4. 比较操作
大小比较
BigDecimal a = new BigDecimal("100.50");
BigDecimal b = new BigDecimal("100.00");
BigDecimal c = new BigDecimal("100.50");// 比较
int compareResult = a.compareTo(b); // 1 (a > b)
boolean isGreater = a.compareTo(b) > 0; // true
boolean isLess = a.compareTo(b) < 0; // false
boolean isEqual = a.compareTo(c) == 0; // true// 不要使用equals进行数值比较(会比较精度)
boolean equals1 = a.equals(b); // false
boolean equals2 = a.equals(new BigDecimal("100.5")); // false(精度不同)
boolean compare1 = a.compareTo(new BigDecimal("100.5")) == 0; // true
范围检查
public class BigDecimalComparison {public static boolean isBetween(BigDecimal value, BigDecimal min, BigDecimal max) {return value.compareTo(min) >= 0 && value.compareTo(max) <= 0;}public static boolean isPositive(BigDecimal value) {return value.compareTo(BigDecimal.ZERO) > 0;}public static boolean isNegative(BigDecimal value) {return value.compareTo(BigDecimal.ZERO) < 0;}public static boolean isZero(BigDecimal value) {return value.compareTo(BigDecimal.ZERO) == 0;}
}
5. 类型转换
转换为其他类型
BigDecimal bd = new BigDecimal("123.456");// 转换为字符串
String stringValue = bd.toString(); // "123.456"
String plainString = bd.toPlainString(); // "123.456"(不使用科学计数法)
String engineeringString = bd.toEngineeringString(); // "123.456"// 转换为数值类型
int intValue = bd.intValue(); // 123(直接截断)
long longValue = bd.longValue(); // 123
float floatValue = bd.floatValue(); // 123.456
double doubleValue = bd.doubleValue(); // 123.456// 安全转换(处理null和异常)
int safeInt = bd.intValueExact(); // 如果非整数会抛出异常
long safeLong = bd.longValueExact(); // 同上
从其他类型转换
// 从字符串转换
BigDecimal fromString = new BigDecimal("123.45");// 从数值类型转换
BigDecimal fromInt = BigDecimal.valueOf(100);
BigDecimal fromLong = BigDecimal.valueOf(100L);
BigDecimal fromDouble = BigDecimal.valueOf(123.456);// 从整数转换
BigDecimal fromInteger = new BigDecimal(100);// 处理null安全的转换
public static BigDecimal safeValueOf(String value) {if (value == null || value.trim().isEmpty()) {return BigDecimal.ZERO;}try {return new BigDecimal(value.trim());} catch (NumberFormatException e) {return BigDecimal.ZERO;}
}
6. 实用工具方法
数学运算
BigDecimal number = new BigDecimal("16");// 绝对值
BigDecimal abs = number.abs();// 取反
BigDecimal negate = number.negate();// 次方运算
BigDecimal power = number.pow(2); // 256// 移动小数点
BigDecimal movePoint = number.movePointRight(2); // 1600
BigDecimal movePointLeft = number.movePointLeft(1); // 1.6
精度操作
BigDecimal number = new BigDecimal("123.456789");// 获取精度相关信息
int scale = number.scale(); // 6(小数位数)
int precision = number.precision(); // 9(总位数)
BigDecimal stripped = number.stripTrailingZeros(); // 去除末尾的0// 检查整数
boolean isInteger = number.scale() <= 0; // false
boolean hasDecimal = number.scale() > 0; // true
7. 在Android中的实际应用
金额计算工具类
public class MoneyUtils {/*** 格式化金额显示*/public static String formatMoney(BigDecimal amount) {if (amount == null) return "¥0.00";DecimalFormat df = new DecimalFormat("¥#,##0.00");return df.format(amount);}/*** 安全地解析金额字符串*/public static BigDecimal parseMoney(String moneyStr) {if (moneyStr == null || moneyStr.trim().isEmpty()) {return BigDecimal.ZERO;}try {// 移除货币符号和逗号String cleaned = moneyStr.replaceAll("[¥$,]", "").trim();return new BigDecimal(cleaned);} catch (NumberFormatException e) {return BigDecimal.ZERO;}}/*** 计算含税价格*/public static BigDecimal calculateTaxIncluded(BigDecimal amount, BigDecimal taxRate) {if (amount == null || taxRate == null) {return BigDecimal.ZERO;}BigDecimal tax = amount.multiply(taxRate).setScale(2, RoundingMode.HALF_UP);return amount.add(tax);}/*** 分配金额(如AA制分摊)*/public static BigDecimal[] splitAmount(BigDecimal total, int parts) {if (total == null || parts <= 0) {return new BigDecimal[0];}BigDecimal[] result = new BigDecimal[parts];BigDecimal partAmount = total.divide(BigDecimal.valueOf(parts), 2, RoundingMode.HALF_UP);// 前n-1个部分使用平均分配for (int i = 0; i < parts - 1; i++) {result[i] = partAmount;}// 最后一部分用总金额减去已分配金额,避免精度损失BigDecimal allocated = partAmount.multiply(BigDecimal.valueOf(parts - 1));result[parts - 1] = total.subtract(allocated);return result;}
}
在Activity中使用
public class PaymentActivity extends AppCompatActivity {private TextView totalAmountView;private EditText quantityEditText;private BigDecimal unitPrice = new BigDecimal("29.99");@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_payment);totalAmountView = findViewById(R.id.totalAmount);quantityEditText = findViewById(R.id.quantity);quantityEditText.addTextChangedListener(new TextWatcher() {@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {calculateTotal();}// 其他方法...});}private void calculateTotal() {try {String quantityStr = quantityEditText.getText().toString();if (quantityStr.isEmpty()) {totalAmountView.setText("¥0.00");return;}BigDecimal quantity = new BigDecimal(quantityStr);BigDecimal total = unitPrice.multiply(quantity).setScale(2, RoundingMode.HALF_UP);totalAmountView.setText(MoneyUtils.formatMoney(total));} catch (NumberFormatException e) {totalAmountView.setText("无效数量");}}/*** 处理折扣计算*/private BigDecimal applyDiscount(BigDecimal original, BigDecimal discountRate) {BigDecimal discount = original.multiply(discountRate).setScale(2, RoundingMode.HALF_UP);return original.subtract(discount);}
}
8. 注意事项
重要提醒
// 1. 始终使用字符串构造BigDecimal来避免精度问题
BigDecimal bad = new BigDecimal(0.1); // 不推荐
BigDecimal good = new BigDecimal("0.1"); // 推荐// 2. 比较使用compareTo而不是equals
BigDecimal a = new BigDecimal("100.0");
BigDecimal b = new BigDecimal("100.00");
boolean wrong = a.equals(b); // false
boolean correct = a.compareTo(b) == 0; // true// 3. 除法一定要指定舍入模式
BigDecimal ten = new BigDecimal("10");
BigDecimal three = new BigDecimal("3");
// BigDecimal error = ten.divide(three); // 会抛出ArithmeticException
BigDecimal correct = ten.divide(three, 2, RoundingMode.HALF_UP); // 3.33// 4. 使用valueOf来处理double(内部会处理精度)
BigDecimal fromDouble = BigDecimal.valueOf(0.1); // 0.1
这些是BigDecimal在Java/Android中的主要转换和操作方法。BigDecimal特别适合财务计算、货币运算等需要高精度的场景。
