尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Java实现金额数字转中文大写金额的算法与实践

Java实现金额数字转中文大写金额的算法与实践 1. 项目背景与核心需求金额数字转大写金额这个功能在财务系统、银行票据、合同文书等场景中极为常见。作为一名Java开发者我经常需要处理这类需求。比如最近在开发一个企业ERP系统时就遇到了发票打印模块需要将12345.67转换为壹万贰仟叁佰肆拾伍元陆角柒分的需求。这个看似简单的功能实际上需要考虑很多边界情况如何处理0在不同位置的表现如1001元要显示壹仟零壹元小数部分的处理规则角、分单位超大金额的支持亿级以上负数的处理金额有效性校验2. 核心算法设计思路2.1 数字与中文的映射关系首先需要建立数字到中文的映射表private static final String[] CN_NUMBERS {零, 壹, 贰, 叁, 肆, 伍, 陆, 柒, 捌, 玖}; private static final String[] CN_UNITS {, 拾, 佰, 仟, 万, 拾, 佰, 仟, 亿};2.2 金额分节处理算法金额转换的核心是将数字按4位一节进行分节处理将整数部分和小数部分分离对整数部分从右至左每4位分一节每节内部处理零的显示规则节与节之间添加万、亿等单位例如123456789.12 → 分节123456789 处理1亿 2345万 67892.3 小数部分处理规则小数部分需要特殊处理小数点后第一位为角小数点后第二位为分如果小数部分全为0则添加整字结尾3. 完整实现代码与解析3.1 基础工具类实现public class MoneyToChineseUtil { private static final String[] CN_NUMBERS {零, 壹, 贰, 叁, 肆, 伍, 陆, 柒, 捌, 玖}; private static final String[] CN_UNITS {, 拾, 佰, 仟, 万, 拾, 佰, 仟, 亿}; private static final String CN_FULL 整; private static final String CN_NEGATIVE 负; private static final String CN_YUAN 元; private static final String CN_JIAO 角; private static final String CN_FEN 分; private static final int MAX_NUMBER 999999999; public static String convert(double amount) { if (Math.abs(amount) MAX_NUMBER) { throw new IllegalArgumentException(金额超出处理范围); } long money Math.round(amount * 100); if (money 0) { return CN_NUMBERS[0] CN_YUAN CN_FULL; } StringBuilder result new StringBuilder(); if (money 0) { money -money; result.append(CN_NEGATIVE); } // 处理整数部分 long integerPart money / 100; int unitIndex 0; boolean zeroFlag true; while (integerPart 0) { int section (int)(integerPart % 10000); if (section 0) { String sectionStr convertSection(section); result.insert(0, sectionStr CN_UNITS[unitIndex]); zeroFlag false; } else { if (!zeroFlag) { result.insert(0, CN_NUMBERS[0]); } zeroFlag true; } integerPart integerPart / 10000; unitIndex 4; } result.append(CN_YUAN); // 处理小数部分 int decimalPart (int)(money % 100); if (decimalPart 0) { result.append(CN_FULL); } else { int jiao decimalPart / 10; int fen decimalPart % 10; if (jiao 0) { result.append(CN_NUMBERS[jiao]).append(CN_JIAO); } if (fen 0) { result.append(CN_NUMBERS[fen]).append(CN_FEN); } } return result.toString(); } private static String convertSection(int section) { StringBuilder sectionStr new StringBuilder(); int unitPos 0; boolean zero true; while (section 0) { int num section % 10; if (num 0) { if (!zero) { zero true; sectionStr.insert(0, CN_NUMBERS[num]); } } else { zero false; sectionStr.insert(0, CN_NUMBERS[num] CN_UNITS[unitPos]); } section section / 10; unitPos; } return sectionStr.toString(); } }3.2 关键代码解析边界处理检查金额范围不超过999,999,999处理0值情况处理负值情况分节处理每4位为一节convertSection方法处理连续的0如1001 → 壹仟零壹添加节单位万、亿小数处理分离角和分处理只有角或只有分的情况4. 测试用例与验证4.1 常规测试用例Test public void testConvert() { assertEquals(壹元整, MoneyToChineseUtil.convert(1)); assertEquals(壹拾元整, MoneyToChineseUtil.convert(10)); assertEquals(壹佰零壹元整, MoneyToChineseUtil.convert(101)); assertEquals(壹仟零壹元整, MoneyToChineseUtil.convert(1001)); assertEquals(壹万贰仟叁佰肆拾伍元陆角柒分, MoneyToChineseUtil.convert(12345.67)); assertEquals(壹亿贰仟叁佰肆拾伍万陆仟柒佰捌拾玖元整, MoneyToChineseUtil.convert(123456789)); assertEquals(负壹元整, MoneyToChineseUtil.convert(-1)); assertEquals(零元整, MoneyToChineseUtil.convert(0)); }4.2 边界测试用例Test(expected IllegalArgumentException.class) public void testOverMax() { MoneyToChineseUtil.convert(1000000000); } Test public void testDecimal() { assertEquals(壹元伍角, MoneyToChineseUtil.convert(1.5)); assertEquals(壹元零伍分, MoneyToChineseUtil.convert(1.05)); assertEquals(壹元伍角伍分, MoneyToChineseUtil.convert(1.55)); }5. 性能优化与注意事项5.1 性能优化点使用StringBuilder避免字符串拼接产生大量临时对象位运算替代除法对于性能敏感场景可用位运算优化除法和取模缓存常用结果对于高频小金额可建立缓存5.2 常见问题与解决精度问题注意不要直接使用double进行金额计算应该使用BigDecimal或转为分处理零的处理规则1001 → 壹仟零壹元1010 → 壹仟零壹拾元1000 → 壹仟元超大金额支持 如果需要支持更大金额可以扩展单位数组private static final String[] CN_UNITS {, 拾, 佰, 仟, 万, 拾, 佰, 仟, 亿, 拾, 佰, 仟, 兆};6. 实际应用扩展6.1 Spring Boot集成方案可以封装为Spring Boot StarterConfiguration public class MoneyConvertAutoConfiguration { Bean public MoneyToChineseUtil moneyToChineseUtil() { return new MoneyToChineseUtil(); } }6.2 多语言支持通过策略模式支持多语言public interface MoneyConverter { String convert(double amount); } public class ChineseMoneyConverter implements MoneyConverter { // 中文实现 } public class EnglishMoneyConverter implements MoneyConverter { // 英文实现 }6.3 银行票据打印实践在银行票据打印中还需要注意金额前加¥符号防止金额被篡改如添加星号填充特殊格式要求如每三位加逗号public String formatForPrint(double amount) { String chinese convert(amount); return ¥ String.format(%,.2f, amount) ( chinese ); }
返回列表