Java/Android中BigDecimal的相关操作

在Java/Android中,BigDecimal 用于高精度的十进制运算。以下是详细的转换和操作方法:

1. 创建和初始化

基本创建方式

java 复制代码
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. 基本算术运算

四则运算

java 复制代码
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

复杂运算示例

java 复制代码
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.97
        System.out.println("税费: $" + tax);      // $24.00
        System.out.println("总计: $" + total);    // $323.97
    }
}

3. 精度控制和舍入

设置精度和舍入模式

java 复制代码
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

舍入模式详解

java 复制代码
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. 比较操作

大小比较

java 复制代码
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

范围检查

java 复制代码
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. 类型转换

转换为其他类型

java 复制代码
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();         // 同上

从其他类型转换

java 复制代码
// 从字符串转换
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. 实用工具方法

数学运算

java 复制代码
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

精度操作

java 复制代码
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中的实际应用

金额计算工具类

java 复制代码
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中使用

java 复制代码
public class PaymentActivity extends AppCompatActivity {
    private TextView totalAmountView;
    private EditText quantityEditText;
    private BigDecimal unitPrice = new BigDecimal("29.99");
    
    @Override
    protected 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() {
            @Override
            public 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. 注意事项

重要提醒

java 复制代码
// 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特别适合财务计算、货币运算等需要高精度的场景。

相关推荐
砖厂小工43 分钟前
用 GLM + OpenClaw 打造你的 AI PR Review Agent — 让龙虾帮你审代码
android·github
张拭心1 小时前
春节后,有些公司明确要求 AI 经验了
android·前端·人工智能
张拭心2 小时前
Android 17 来了!新特性介绍与适配建议
android·前端
SimonKing3 小时前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员
FastBean3 小时前
Jackson View Extension Spring Boot Starter
java·后端
Kapaseker4 小时前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴4 小时前
Android17 为什么重写 MessageQueue
android
Seven974 小时前
剑指offer-79、最⻓不含重复字符的⼦字符串
java
皮皮林55114 小时前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java
冰_河14 小时前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化