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

相关推荐
普通网友2 小时前
嵌入式C++安全编码
开发语言·c++·算法
烤麻辣烫2 小时前
黑马程序员苍穹外卖(新手) DAY3
java·开发语言·spring boot·学习·intellij-idea
q***48252 小时前
基于python语言的网页设计(手把手教你设计一个个人博客网站)
开发语言·python
妮妮喔妮2 小时前
JAVA反射的介绍(优缺点)
java·开发语言
云知谷2 小时前
【软件测试】《集成测试全攻略:Mock/Stub 原理 + Postman/JUnit/TestNG 实战》
c语言·开发语言·c++·软件工程·团队开发
i***48612 小时前
Redis重大版本整理(Redis2.6-Redis7.0)
java·数据库·redis
YQ_ZJH2 小时前
Redisson 看门狗机制详解
java·redis
那我掉的头发算什么2 小时前
【javaEE】多线程——线程安全进阶☆☆☆
java·jvm·安全·java-ee·intellij-idea
qq_22589174662 小时前
基于Python+Django餐饮评论大数据分析与智能推荐系统 毕业论文
开发语言·后端·python·信息可视化·数据分析·django