BigDecimal案例

wen java案例 3

本文目录导读:

BigDecimal案例

  1. 金额计算场景(电商)
  2. 银行账户利息计算
  3. 汇率转换
  4. 精确比较和范围判断
  5. 完整的分账系统案例
  6. 精度运算注意点
  7. 最佳实践建议:

我来为您提供几个BigDecimal的实用案例,涵盖常见业务场景:

金额计算场景(电商)

import java.math.BigDecimal;
import java.math.RoundingMode;
public class MoneyCalculation {
    public static void main(String[] args) {
        // 商品价格
        BigDecimal price = new BigDecimal("199.90");
        BigDecimal quantity = new BigDecimal("3");
        BigDecimal discountRate = new BigDecimal("0.85"); // 85折
        // 计算原价
        BigDecimal originalPrice = price.multiply(quantity);
        System.out.println("原价:" + originalPrice);
        // 计算折扣价
        BigDecimal discountPrice = originalPrice.multiply(discountRate);
        System.out.println("折扣价:" + discountPrice);
        // 四舍五入到分(保留2位小数)
        BigDecimal finalPrice = discountPrice.setScale(2, RoundingMode.HALF_UP);
        System.out.println("最终价格:" + finalPrice);
        // 计算税额(13%增值税)
        BigDecimal taxRate = new BigDecimal("0.13");
        BigDecimal taxAmount = finalPrice.multiply(taxRate).setScale(2, RoundingMode.HALF_UP);
        System.out.println("税额:" + taxAmount);
        // 含税总价
        BigDecimal totalWithTax = finalPrice.add(taxAmount);
        System.out.println("含税总价:" + totalWithTax);
    }
}

银行账户利息计算

import java.math.BigDecimal;
import java.math.RoundingMode;
public class InterestCalculation {
    public static void main(String[] args) {
        // 存款本金
        BigDecimal principal = new BigDecimal("100000.00");
        // 年利率 2.5%
        BigDecimal annualRate = new BigDecimal("0.025");
        // 存期(年)
        int years = 3;
        BigDecimal total = principal;
        // 复利计算
        for (int i = 0; i < years; i++) {
            BigDecimal interest = total.multiply(annualRate)
                    .setScale(2, RoundingMode.HALF_UP);
            total = total.add(interest);
            System.out.printf("第%d年:利息%s,总额%s%n", i+1, interest, total);
        }
        // 获取整数部分和小数部分
        BigDecimal interestEarned = total.subtract(principal);
        BigDecimal intPart = total.toBigInteger().bigDecimalValue();
        BigDecimal decPart = total.remainder(BigDecimal.ONE);
        System.out.println("总利息:" + interestEarned);
        System.out.println("整数部分:" + intPart);
        System.out.println("小数部分:" + decPart);
    }
}

汇率转换

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
public class CurrencyExchange {
    private static Map<String, BigDecimal> exchangeRates = new HashMap<>();
    static {
        // 币种对美元汇率
        exchangeRates.put("USD", new BigDecimal("1.0000"));
        exchangeRates.put("CNY", new BigDecimal("7.2450"));
        exchangeRates.put("EUR", new BigDecimal("0.9250"));
        exchangeRates.put("JPY", new BigDecimal("149.5000"));
    }
    public static BigDecimal convert(BigDecimal amount, String fromCurrency, String toCurrency) {
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("金额必须大于0");
        }
        BigDecimal fromRate = exchangeRates.get(fromCurrency);
        BigDecimal toRate = exchangeRates.get(toCurrency);
        if (fromRate == null || toRate == null) {
            throw new IllegalArgumentException("不支持的货币类型");
        }
        // 转换公式: amount * (toRate / fromRate)
        BigDecimal result = amount.multiply(toRate.divide(fromRate, 8, RoundingMode.HALF_UP));
        // 保留2位小数,四舍五入
        return result.setScale(2, RoundingMode.HALF_UP);
    }
    public static void main(String[] args) {
        // 1000美元兑换人民币
        BigDecimal usdAmount = new BigDecimal("1000.00");
        BigDecimal cnyResult = convert(usdAmount, "USD", "CNY");
        System.out.println("1000美元 = " + cnyResult + "人民币");
        // 10000日元兑换欧元
        BigDecimal jpyAmount = new BigDecimal("10000");
        BigDecimal eurResult = convert(jpyAmount, "JPY", "EUR");
        System.out.println("10000日元 = " + eurResult + "欧元");
    }
}

精确比较和范围判断

import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalComparison {
    public static void main(String[] args) {
        BigDecimal creditLimit = new BigDecimal("50000.00");
        BigDecimal frozenAmount = new BigDecimal("5000.00");
        BigDecimal availableAmount = creditLimit.subtract(frozenAmount);
        // 业务场景:验证交易金额
        BigDecimal transactionAmount = new BigDecimal("45000.00");
        // 检查交易金额是否超过可用额度
        if (transactionAmount.compareTo(availableAmount) > 0) {
            System.out.println("交易金额超限!");
            System.out.println("可用额度:" + availableAmount);
            System.out.println("交易金额:" + transactionAmount);
        } else {
            System.out.println("交易成功,可用额度足够");
        }
        // 检查金额是否在某个范围内
        BigDecimal minAmount = new BigDecimal("10.00");
        BigDecimal maxAmount = new BigDecimal("1000.00");
        // 验证输入金额是否在有效范围内
        BigDecimal inputAmount = new BigDecimal("999.99");
        boolean inRange = inputAmount.compareTo(minAmount) >= 0 
                         && inputAmount.compareTo(maxAmount) <= 0;
        if (inRange) {
            System.out.println("金额在有效范围内");
        } else {
            System.out.println("金额超出有效范围");
        }
        // 判断金额是否接近某个值(误差处理)
        BigDecimal targetValue = new BigDecimal("100");
        BigDecimal actualValue = new BigDecimal("99.99");
        BigDecimal tolerance = new BigDecimal("0.05");
        BigDecimal diff = actualValue.subtract(targetValue).abs();
        if (diff.compareTo(tolerance) <= 0) {
            System.out.println("金额在允许误差范围内");
        }
    }
}

完整的分账系统案例

import java.math.BigDecimal;
import java.math.RoundingMode;
public class SplitAccount {
    public static void main(String[] args) {
        // 订单总金额
        BigDecimal orderTotal = new BigDecimal("1000.00");
        // 分账比例设置
        BigDecimal platformRate = new BigDecimal("0.20");
        BigDecimal merchantRate = new BigDecimal("0.80");
        // 计算分账金额(保留2位小数)
        BigDecimal platformAmount = orderTotal.multiply(platformRate)
                .setScale(2, RoundingMode.HALF_UP);
        BigDecimal merchantAmount = orderTotal.multiply(merchantRate)
                .setScale(2, RoundingMode.HALF_UP);
        System.out.println("订单总额:" + orderTotal);
        System.out.println("平台分成(20%):" + platformAmount);
        System.out.println("商家分成(80%):" + merchantAmount);
        // 验证分账是否完整(可能因为四舍五入有误差)
        BigDecimal totalAllocated = platformAmount.add(merchantAmount);
        BigDecimal difference = orderTotal.subtract(totalAllocated);
        System.out.println("差异金额:" + difference);
        // 如果存在差异,调整商家金额(确保总额一致)
        if (difference.compareTo(BigDecimal.ZERO) != 0) {
            merchantAmount = merchantAmount.add(difference);
            System.out.println("调整后商家金额:" + merchantAmount);
            System.out.println("调整后分配总额:" + platformAmount.add(merchantAmount));
        }
    }
}

精度运算注意点

import java.math.BigDecimal;
import java.math.RoundingMode;
public class PrecisionTips {
    public static void main(String[] args) {
        // 1. 避免使用double构造
        BigDecimal wrong1 = new BigDecimal(0.1);  // 不精确
        BigDecimal correct1 = new BigDecimal("0.1");  // 精确
        System.out.println("double构造:" + wrong1);
        System.out.println("字符串构造:" + correct1);
        // 2. 除以零的处理
        BigDecimal number = new BigDecimal("10");
        BigDecimal divisor = BigDecimal.ZERO;
        try {
            number.divide(divisor);
        } catch (ArithmeticException e) {
            System.out.println("除以零异常:不能将BigDecimal除以0");
        }
        // 3. 无限小数处理,必须指定精度
        BigDecimal numerator = new BigDecimal("1");
        BigDecimal denominator = new BigDecimal("3");
        // 如果不指定舍入模式会报错
        try {
            numerator.divide(denominator);
        } catch (ArithmeticException e) {
            System.out.println("无限小数必须指定精度:" + e.getMessage());
        }
        // 正确方式
        BigDecimal result = numerator.divide(denominator, 4, RoundingMode.HALF_UP);
        System.out.println("1/3 = " + result);
        // 4. 常量使用
        BigDecimal constZero = BigDecimal.ZERO;
        BigDecimal constOne = BigDecimal.ONE;
        BigDecimal constTen = BigDecimal.TEN;
        System.out.println("常用常量:" + constZero + ", " + constOne + ", " + constTen);
    }
}

最佳实践建议:

  1. 构造BigDecimal时使用字符串,避免精度丢失
  2. 除法运算必须指定精度和舍入模式
  3. 使用 compareTo() 而不是 equals() 比较大小
  4. 金额计算保留2位小数(分),使用 HALF_UP 舍入
  5. 考虑小数位数和精度需求,避免不必要的精度损失
  6. 存储到数据库时使用 String 类型或 DECIMAL 类型

这些案例覆盖了BigDecimal的主要使用场景,实际开发中可以根据业务需求进行调整和扩展。

抱歉,评论功能暂时关闭!