Java金额计算案例

wen java案例 2

本文目录导读:

Java金额计算案例

  1. 基础金额计算(使用BigDecimal)
  2. 订单金额计算服务
  3. 分期付款计算器
  4. 汇率转换器
  5. 金额工具类(最佳实践)

我将为您提供几个Java金额计算的完整案例,涵盖常见的业务场景和最佳实践。

基础金额计算(使用BigDecimal)

import java.math.BigDecimal;
import java.math.RoundingMode;
public class BasicAmountCalculation {
    public static void main(String[] args) {
        // 商品价格
        BigDecimal price = new BigDecimal("199.99");
        int quantity = 3;
        // 计算总价
        BigDecimal totalPrice = calculateTotalPrice(price, quantity);
        System.out.println("商品单价: " + price + " 元");
        System.out.println("购买数量: " + quantity + " 件");
        System.out.println("商品总价: " + totalPrice + " 元");
        // 计算折扣后的价格
        BigDecimal discountRate = new BigDecimal("0.85"); // 85折
        BigDecimal discountedPrice = applyDiscount(totalPrice, discountRate);
        System.out.println("折扣后金额: " + discountedPrice + " 元");
        // 计算税费(10%税率)
        BigDecimal taxRate = new BigDecimal("0.10");
        BigDecimal taxAmount = calculateTax(discountedPrice, taxRate);
        System.out.println("税费金额: " + taxAmount + " 元");
        // 最终应付金额
        BigDecimal finalAmount = discountedPrice.add(taxAmount);
        System.out.println("最终应付: " + finalAmount + " 元");
    }
    /**
     * 计算总价
     */
    public static BigDecimal calculateTotalPrice(BigDecimal price, int quantity) {
        return price.multiply(BigDecimal.valueOf(quantity))
                   .setScale(2, RoundingMode.HALF_UP);
    }
    /**
     * 应用折扣
     */
    public static BigDecimal applyDiscount(BigDecimal amount, BigDecimal discountRate) {
        return amount.multiply(discountRate)
                    .setScale(2, RoundingMode.HALF_UP);
    }
    /**
     * 计算税费
     */
    public static BigDecimal calculateTax(BigDecimal amount, BigDecimal taxRate) {
        return amount.multiply(taxRate)
                    .setScale(2, RoundingMode.HALF_UP);
    }
}

订单金额计算服务

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
/**
 * 订单金额计算服务
 */
public class OrderAmountCalculator {
    // 订单项
    static class OrderItem {
        private String productName;
        private BigDecimal unitPrice;
        private int quantity;
        private BigDecimal discountRate; // 单项折扣,1.0表示无折扣
        public OrderItem(String productName, BigDecimal unitPrice, int quantity) {
            this(productName, unitPrice, quantity, new BigDecimal("1.0"));
        }
        public OrderItem(String productName, BigDecimal unitPrice, int quantity, BigDecimal discountRate) {
            this.productName = productName;
            this.unitPrice = unitPrice;
            this.quantity = quantity;
            this.discountRate = discountRate;
        }
        public BigDecimal getSubtotal() {
            return unitPrice.multiply(BigDecimal.valueOf(quantity))
                          .multiply(discountRate)
                          .setScale(2, RoundingMode.HALF_UP);
        }
    }
    static class Order {
        private List<OrderItem> items;
        private BigDecimal shippingFee;
        private BigDecimal taxRate;
        public Order() {
            this.items = new ArrayList<>();
            this.shippingFee = new BigDecimal("0");
            this.taxRate = new BigDecimal("0.10"); // 10% 税率
        }
        public void addItem(OrderItem item) {
            items.add(item);
        }
        public void setShippingFee(BigDecimal shippingFee) {
            this.shippingFee = shippingFee;
        }
        // 商品总金额
        public BigDecimal getItemsTotal() {
            BigDecimal total = BigDecimal.ZERO;
            for (OrderItem item : items) {
                total = total.add(item.getSubtotal());
            }
            return total.setScale(2, RoundingMode.HALF_UP);
        }
        // 免运费门槛判断(通常满100免运费)
        public boolean isFreeShipping() {
            return getItemsTotal().compareTo(new BigDecimal("100")) >= 0;
        }
        // 实际运费
        public BigDecimal getActualShippingFee() {
            if (isFreeShipping()) {
                return BigDecimal.ZERO;
            }
            return shippingFee;
        }
        // 税费
        public BigDecimal getTax() {
            return getItemsTotal().multiply(taxRate)
                                 .setScale(2, RoundingMode.HALF_UP);
        }
        // 订单总额
        public BigDecimal getGrandTotal() {
            return getItemsTotal()
                    .add(getActualShippingFee())
                    .add(getTax())
                    .setScale(2, RoundingMode.HALF_UP);
        }
        // 打印订单详情
        public void printOrderDetails() {
            System.out.println("========== 订单详情 ==========");
            for (OrderItem item : items) {
                System.out.printf("%s x%d = %.2f元%n", 
                    item.productName, 
                    item.quantity, 
                    item.getSubtotal());
            }
            System.out.println("------------------------------");
            System.out.println("商品总金额: " + getItemsTotal() + " 元");
            System.out.println("运费: " + getActualShippingFee() + " 元");
            System.out.println("税费(10%): " + getTax() + " 元");
            System.out.println("订单总额: " + getGrandTotal() + " 元");
        }
    }
    public static void main(String[] args) {
        // 创建订单
        Order order = new Order();
        // 添加商品
        order.addItem(new OrderItem("iPhone 15", new BigDecimal("6999.00"), 1));
        order.addItem(new OrderItem("手机壳", new BigDecimal("49.90"), 2, new BigDecimal("0.95")));
        order.addItem(new OrderItem("钢化膜", new BigDecimal("19.90"), 3));
        // 设置运费
        order.setShippingFee(new BigDecimal("10.00"));
        // 打印订单详情
        order.printOrderDetails();
    }
}

分期付款计算器

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
/**
 * 分期付款计算器
 */
public class InstallmentCalculator {
    static class InstallmentPlan {
        private BigDecimal principal;      // 本金
        private BigDecimal annualRate;     // 年利率
        private int months;                // 分期期数
        private BigDecimal monthlyRate;    // 月利率
        public InstallmentPlan(BigDecimal principal, BigDecimal annualRate, int months) {
            this.principal = principal;
            this.annualRate = annualRate;
            this.months = months;
            this.monthlyRate = annualRate.divide(new BigDecimal("12"), 10, RoundingMode.HALF_UP);
        }
        // 等额本息每月还款额
        public BigDecimal getMonthlyPayment() {
            if (months == 0) return principal;
            // 公式: 每月还款 = P * r * (1+r)^n / ((1+r)^n - 1)
            BigDecimal monthlyRate = this.monthlyRate;
            // 计算 (1+r)^n
            BigDecimal power = BigDecimal.ONE;
            for (int i = 0; i < months; i++) {
                power = power.multiply(BigDecimal.ONE.add(monthlyRate));
            }
            // 分子: P * r * (1+r)^n
            BigDecimal numerator = principal
                    .multiply(monthlyRate)
                    .multiply(power);
            // 分母: (1+r)^n - 1
            BigDecimal denominator = power.subtract(BigDecimal.ONE);
            return numerator.divide(denominator, 2, RoundingMode.HALF_UP);
        }
        // 总还款额
        public BigDecimal getTotalPayment() {
            return getMonthlyPayment().multiply(BigDecimal.valueOf(months))
                                     .setScale(2, RoundingMode.HALF_UP);
        }
        // 总利息
        public BigDecimal getTotalInterest() {
            return getTotalPayment().subtract(principal)
                                   .setScale(2, RoundingMode.HALF_UP);
        }
        // 生成还款计划表
        public List<PaymentDetail> getPaymentSchedule() {
            List<PaymentDetail> schedule = new ArrayList<>();
            BigDecimal remainingBalance = principal;
            BigDecimal monthlyPayment = getMonthlyPayment();
            for (int month = 1; month <= months; month++) {
                BigDecimal interest = remainingBalance
                        .multiply(monthlyRate)
                        .setScale(2, RoundingMode.HALF_UP);
                BigDecimal principalPart = monthlyPayment.subtract(interest);
                BigDecimal previousBalance = remainingBalance;
                remainingBalance = remainingBalance.subtract(principalPart)
                                                 .max(BigDecimal.ZERO);
                schedule.add(new PaymentDetail(month, monthlyPayment, principalPart, 
                                             interest, previousBalance, remainingBalance));
            }
            return schedule;
        }
        // 打印计划
        public void printSchedule() {
            System.out.println("===== 分期付款计划 =====");
            System.out.println("本金: " + principal + " 元");
            System.out.println("年利率: " + annualRate.multiply(new BigDecimal("100")) + "%");
            System.out.println("分期期数: " + months + " 个月");
            System.out.println("每月还款: " + getMonthlyPayment() + " 元");
            System.out.println("总利息: " + getTotalInterest() + " 元");
            System.out.println("总还款: " + getTotalPayment() + " 元");
            System.out.println();
            System.out.println("--- 还款明细 ---");
            System.out.printf("%-6s %-12s %-12s %-12s %-12s %-12s%n", 
                "期数", "月还款额", "本金", "利息", "剩余本金", "上期余额");
            for (PaymentDetail detail : getPaymentSchedule()) {
                System.out.printf("%-6d %-12.2f %-12.2f %-12.2f %-12.2f %-12.2f%n",
                    detail.month, detail.payment, detail.principal, detail.interest,
                    detail.balance, detail.previousBalance);
            }
        }
    }
    // 还款明细类
    static class PaymentDetail {
        int month;
        BigDecimal payment;         // 月还款额
        BigDecimal principal;       // 本金部分
        BigDecimal interest;        // 利息部分
        BigDecimal previousBalance; // 上期剩余本金
        BigDecimal balance;         // 本期剩余本金
        public PaymentDetail(int month, BigDecimal payment, BigDecimal principal, 
                           BigDecimal interest, BigDecimal previousBalance, BigDecimal balance) {
            this.month = month;
            this.payment = payment;
            this.principal = principal;
            this.interest = interest;
            this.previousBalance = previousBalance;
            this.balance = balance;
        }
    }
    public static void main(String[] args) {
        // 贷款10000元,年利率5%,分12期
        InstallmentPlan plan = new InstallmentPlan(
            new BigDecimal("10000.00"),
            new BigDecimal("0.05"),
            12
        );
        plan.printSchedule();
    }
}

汇率转换器

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
/**
 * 汇率转换器
 */
public class CurrencyConverter {
    private Map<String, Map<String, BigDecimal>> exchangeRates;
    public CurrencyConverter() {
        exchangeRates = new HashMap<>();
        initRates();
    }
    private void initRates() {
        // 以人民币(CNY)为基准的汇率
        Map<String, BigDecimal> cnyRates = new HashMap<>();
        cnyRates.put("USD", new BigDecimal("0.139"));  // 1 CNY = 0.139 USD
        cnyRates.put("EUR", new BigDecimal("0.128"));  // 1 CNY = 0.128 EUR
        cnyRates.put("GBP", new BigDecimal("0.110"));  // 1 CNY = 0.110 GBP
        cnyRates.put("JPY", new BigDecimal("20.500")); // 1 CNY = 20.5 JPY
        exchangeRates.put("CNY", cnyRates);
    }
    /**
     * 货币转换
     * @param amount 金额
     * @param fromCurrency 源货币
     * @param toCurrency 目标货币
     * @return 转换后的金额
     */
    public BigDecimal convert(BigDecimal amount, String fromCurrency, String toCurrency) {
        if (fromCurrency.equals(toCurrency)) {
            return amount.setScale(2, RoundingMode.HALF_UP);
        }
        // 先转换为人民币
        BigDecimal amountInCNY;
        if (fromCurrency.equals("CNY")) {
            amountInCNY = amount;
        } else {
            // 从其他货币转到人民币,需要倒数
            Map<String, BigDecimal> cnyRates = exchangeRates.get("CNY");
            BigDecimal rate = cnyRates.get(fromCurrency);
            amountInCNY = amount.divide(rate, 10, RoundingMode.HALF_UP);
        }
        // 从人民币转换为目标货币
        Map<String, BigDecimal> cnyRates = exchangeRates.get("CNY");
        BigDecimal targetRate = cnyRates.get(toCurrency);
        if (targetRate == null) {
            throw new IllegalArgumentException("不支持的货币: " + toCurrency);
        }
        return amountInCNY.multiply(targetRate)
                         .setScale(2, RoundingMode.HALF_UP);
    }
    public static void main(String[] args) {
        CurrencyConverter converter = new CurrencyConverter();
        // 转换示例
        BigDecimal amountInCNY = new BigDecimal("1000.00");
        System.out.println("1000人民币转换结果:");
        System.out.println("美元(USD): " + converter.convert(amountInCNY, "CNY", "USD"));
        System.out.println("欧元(EUR): " + converter.convert(amountInCNY, "CNY", "EUR"));
        System.out.println("英镑(GBP): " + converter.convert(amountInCNY, "CNY", "GBP"));
        System.out.println("日元(JPY): " + converter.convert(amountInCNY, "CNY", "JPY"));
        // 逆转换
        BigDecimal usdAmount = converter.convert(amountInCNY, "CNY", "USD");
        System.out.println("\n1000美元转换回人民币: " + 
            converter.convert(usdAmount, "USD", "CNY"));
    }
}

金额工具类(最佳实践)

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Currency;
import java.util.Locale;
/**
 * 金额工具类 - 企业级金额处理规范
 */
public final class AmountUtil {
    private static final int DEFAULT_SCALE = 2;
    private static final RoundingMode DEFAULT_ROUNDING = RoundingMode.HALF_UP;
    private static final BigDecimal ONE_HUNDRED = new BigDecimal("100");
    private AmountUtil() {
        // 私有构造函数,防止实例化
    }
    /**
     * 创建安全的BigDecimal金额
     */
    public static BigDecimal createAmount(String value) {
        if (value == null || value.trim().isEmpty()) {
            throw new IllegalArgumentException("金额不能为空");
        }
        return new BigDecimal(value).setScale(DEFAULT_SCALE, DEFAULT_ROUNDING);
    }
    /**
     * 金额累加
     */
    public static BigDecimal add(BigDecimal... amounts) {
        BigDecimal result = BigDecimal.ZERO;
        for (BigDecimal amount : amounts) {
            if (amount != null) {
                result = result.add(amount);
            }
        }
        return result.setScale(DEFAULT_SCALE, DEFAULT_ROUNDING);
    }
    /**
     * 金额相减
     */
    public static BigDecimal subtract(BigDecimal minuend, BigDecimal subtrahend) {
        if (minuend == null || subtrahend == null) {
            throw new IllegalArgumentException("金额不能为null");
        }
        return minuend.subtract(subtrahend).setScale(DEFAULT_SCALE, DEFAULT_ROUNDING);
    }
    /**
     * 金额乘法
     */
    public static BigDecimal multiply(BigDecimal amount, BigDecimal multiplier) {
        if (amount == null || multiplier == null) {
            throw new IllegalArgumentException("参数不能为null");
        }
        return amount.multiply(multiplier).setScale(DEFAULT_SCALE, DEFAULT_ROUNDING);
    }
    /**
     * 金额除法
     */
    public static BigDecimal divide(BigDecimal dividend, BigDecimal divisor) {
        if (dividend == null || divisor == null) {
            throw new IllegalArgumentException("参数不能为null");
        }
        if (divisor.compareTo(BigDecimal.ZERO) == 0) {
            throw new ArithmeticException("除数不能为零");
        }
        return dividend.divide(divisor, DEFAULT_SCALE, DEFAULT_ROUNDING);
    }
    /**
     * 百分比转换(金额 * 百分数值)
     */
    public static BigDecimal percent(BigDecimal amount, BigDecimal percent) {
        if (percent == null || percent.compareTo(BigDecimal.ZERO) < 0) {
            throw new IllegalArgumentException("百分比必须为非负数");
        }
        return amount.multiply(percent)
                    .divide(ONE_HUNDRED, DEFAULT_SCALE, DEFAULT_ROUNDING);
    }
    /**
     * 安全比较金额大小
     */
    public static int compare(BigDecimal amount1, BigDecimal amount2) {
        if (amount1 == null || amount2 == null) {
            throw new IllegalArgumentException("金额不能为null");
        }
        return amount1.compareTo(amount2);
    }
    /**
     * 是否相等
     */
    public static boolean equals(BigDecimal amount1, BigDecimal amount2) {
        return amount1 != null && amount2 != null && 
               amount1.compareTo(amount2) == 0;
    }
    /**
     * 金额格式化(带货币符号)
     */
    public static String formatCurrency(BigDecimal amount, Locale locale) {
        if (amount == null) {
            return "";
        }
        NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(locale);
        return currencyFormat.format(amount.doubleValue());
    }
    /**
     * 金额格式化(不带货币符号,千分位)
     */
    public static String formatNumber(BigDecimal amount) {
        if (amount == null) {
            return "0.00";
        }
        DecimalFormat df = new DecimalFormat("#,##0.00");
        return df.format(amount);
    }
    /**
     * 转换为人民币大写金额
     */
    public static String toChineseRMB(BigDecimal amount) {
        if (amount == null || amount.compareTo(BigDecimal.ZERO) == 0) {
            return "零元整";
        }
        if (amount.compareTo(BigDecimal.ZERO) < 0) {
            return "负" + toChineseRMB(amount.abs());
        }
        String[] digits = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
        String[] units = {"", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿"};
        String result = "";
        // 分离整数和小数部分
        BigDecimal scaledAmount = amount.setScale(2, RoundingMode.HALF_UP);
        String[] parts = scaledAmount.toString().split("\\.");
        String integerPart = parts[0];
        String decimalPart = parts.length > 1 ? parts[1] : "";
        // 转换整数部分
        int intLength = integerPart.length();
        for (int i = 0; i < intLength; i++) {
            int digit = integerPart.charAt(i) - '0';
            int unitIndex = intLength - i - 1;
            if (digit != 0) {
                result += digits[digit] + units[unitIndex];
            } else if (i > 0 && integerPart.charAt(i - 1) != '0' && 
                       units[unitIndex].length() > 0) {
                result += "零";
            }
        }
        result += "元";
        // 转换小数部分
        if (decimalPart.length() > 0) {
            int jiao = decimalPart.charAt(0) - '0';
            if (jiao > 0) {
                result += digits[jiao] + "角";
            }
            if (decimalPart.length() > 1) {
                int fen = decimalPart.charAt(1) - '0';
                if (fen > 0) {
                    result += digits[fen] + "分";
                }
            }
        }
        if (!result.contains("角") && !result.contains("分")) {
            result += "整";
        }
        return result;
    }
    /**
     * 测试
     */
    public static void main(String[] args) {
        // 测试金额计算
        BigDecimal price = AmountUtil.createAmount("199.99");
        BigDecimal quantity = new BigDecimal("3");
        BigDecimal total = AmountUtil.multiply(price, quantity);
        System.out.println("商品总价: " + AmountUtil.formatNumber(total));
        System.out.println("含税金额(13%): " + 
            AmountUtil.formatNumber(AmountUtil.add(total, AmountUtil.percent(total, new BigDecimal("13")))));
        // 测试人民币大写
        BigDecimal amount = new BigDecimal("12345.67");
        System.out.println("\n金额: " + amount);
        System.out.println("人民币大写: " + AmountUtil.toChineseRMB(amount));
        // 测试格式化
        System.out.println("\n格式化示例:");
        System.out.println("¥: " + AmountUtil.formatCurrency(amount, Locale.CHINA));
        System.out.println("$: " + AmountUtil.formatCurrency(amount, Locale.US));
    }
}

使用BigDecimal而非double/float

  • doublefloat 存在精度问题
  • 所有金额计算必须使用 BigDecimal

设置合适的精度和舍入模式

BigDecimal amount = new BigDecimal("10.005")
    .setScale(2, RoundingMode.HALF_UP);  // 四舍五入

使用字符串构造BigDecimal

// 正确方式
BigDecimal amount = new BigDecimal("19.99");
// 错误方式(可能产生精度问题)
BigDecimal amount = new BigDecimal(19.99);

金额比较使用compareTo

// 正确方式
amount1.compareTo(amount2) == 0;
// 错误方式(可能不准确)
amount1.equals(amount2);

常见金额场景处理

  • 下单计算:包含商品金额、运费、折扣、税费
  • 支付处理:金额验证、支付成功金额核对
  • 退款处理:原路退回,计算手续费
  • 账户余额:存、取、利息计算

这些示例涵盖了Java金额计算的主要场景,您可以根据实际需求进行调整和扩展。

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