DecimalFormat 与 BigDecimal

一、DecimalFormat:数字格式化类

DecimalFormat是java.text包下的类,专门用于将数字(整数、浮点数)格式化为指定格式的字符串,支持千分位分隔、固定小数位、补 0 等需求。其核心是通过格式模式字符串定义输出格式。

1. 格式模式符号说明

先明确几个常用的格式符号含义:

  • #:表示任意数字,不存在则不显示(例如格式#.##,数字 1.2 会显示为1.2,而非1.20);
  • ,:千分位分隔符(每三位数字分隔,如 1234567 会显示为1,234,567);
  • .:小数点分隔符,用于区分整数部分和小数部分;
  • 0:表示数字,不存在则补 0(例如格式0.00,数字 1.2 会显示为1.20)。

2. 示例:格式化大额数字与固定小数位

java 复制代码
import java.text.DecimalFormat;
 
public class Test {
    public static void main(String[] args) {
        // 定义格式:千分位分隔,保留4位小数
        DecimalFormat decimalFormat = new DecimalFormat("###,###.0000");
        // 格式化数字12553456.598795
        System.out.println(decimalFormat.format(12553456.598795));
    }

输出结果: 12,553,456.5988

解析: 格式###,###.0000中,###,###表示整数部分每三位用逗号分隔(千分位); .0000表示小数部分固定保留 4 位,不足则补 0,超出则四舍五入(原数字小数位是598795,四舍五入后为5988)。

3. 更多格式化场景示例

除了示例中的格式,DecimalFormat还支持多种实用格式,举例如下:

java 复制代码
public class DecimalFormatDemo {
    public static void main(String[] args) {
        // 1. 整数部分补0(如固定3位整数,不足补0)
        DecimalFormat df1 = new DecimalFormat("000");
        System.out.println(df1.format(5)); // 输出:005
        
        // 2. 保留2位小数,整数部分千分位
        DecimalFormat df2 = new DecimalFormat("###,###.00");
        System.out.println(df2.format(123456.7)); // 输出:123,456.70
        
        // 3. 百分比格式(数字×100后加%)
        DecimalFormat df3 = new DecimalFormat("0.00%");
        System.out.println(df3.format(0.356)); // 输出:35.60%
        
        // 4. 科学计数法(保留2位小数)
        DecimalFormat df4 = new DecimalFormat("0.00E0");
        System.out.println(df4.format(123456)); // 输出:1.23E5(即1.23×10^5)
    }

4. 四舍五入说明

舍入模式 0.125 的结果
HALF_UP (标准四舍五入) 0.13
HALF_EVEN (银行家舍入法) 默认 0.12
UP (向上舍入) 0.13
DOWN (向下舍入) 0.12
java 复制代码
DecimalFormat formatter = new DecimalFormat("#.##");
formatter.setRoundingMode(RoundingMode.HALF_UP);  // 设置为标准四舍五入

**核心总结:**DecimalFormat的关键是通过格式模式字符串定义规则,其中#和0用于控制数字位数(0强制补 0,#不强制),,用于千分位,.用于分隔整数和小数部分。

二、BigDecimal:高精度数值计算类

float和double是 Java 中的基本浮点类型,但由于二进制存储的特性,它们无法精确表示所有十进制小数(例如0.1用 double 存储时实际是近似值),在金融、电商等对精度要求极高的场景中会导致误差(如金额计算错误)。

BigDecimal是java.math包下的类,支持任意精度的数值计算,完美解决浮点精度问题。

1. 为什么需要 BigDecimal?

先看一个反例:用double计算 0.1+0.2 的结果:

java 复制代码
System.out.println(0.1 + 0.2); // 输出:0.30000000000000004(存在精度误差)

这是因为0.1和0.2在二进制中无法精确表示,累加后误差被放大。而BigDecimal可以避免这种问题:

java 复制代码
import java.math.BigDecimal;
 
public class BigDecimalDemo {
    public static void main(String[] args) {
        BigDecimal a = new BigDecimal("0.1");
        BigDecimal b = new BigDecimal("0.2");
        System.out.println(a.add(b)); // 输出:0.3(精确计算)
    }

2. 基本用法:创建与运算

BigDecimal的创建和加法运算:

java 复制代码
// 创建BigDecimal对象(注意:不推荐用double构造,原因见下文)
BigDecimal bigDecimal = new BigDecimal(1.555555555555555);
BigDecimal bigDecimal1 = new BigDecimal(2.999999999999);
// 加法运算
System.out.println(bigDecimal.add(bigDecimal1));
// 输出结果(可能存在误差):
4.555555555554555

这里有个坑:用double作为参数构造BigDecimal时,由于double本身的精度问题,BigDecimal会保留其近似值,导致计算结果仍有误差。推荐用String作为构造参数,确保精度:

java 复制代码
// 正确写法:用String构造
BigDecimal a = new BigDecimal("1.555555555555555");
BigDecimal b = new BigDecimal("2.999999999999");
System.out.println(a.add(b)); // 输出:4.555555555554555(精确)

3. 常用运算方法

BigDecimal提供了丰富的运算方法,支持加减乘除等操作,注意运算后需用变量接收结果(BigDecimal是不可变类,运算不会修改原对象):

java 复制代码
public class BigDecimalOperation {
    public static void main(String[] args) {
        BigDecimal a = new BigDecimal("10.5");
        BigDecimal b = new BigDecimal("3");
        
        // 加法
        BigDecimal sum = a.add(b);
        System.out.println("和:" + sum); // 输出:13.5
        
        // 减法
        BigDecimal sub = a.subtract(b);
        System.out.println("差:" + sub); // 输出:7.5
        
        // 乘法
        BigDecimal mul = a.multiply(b);
        System.out.println("积:" + mul); // 输出:31.5
        
        // 除法(需指定保留小数位和舍入模式,避免除不尽报错)
        BigDecimal div = a.divide(b, 2, BigDecimal.ROUND_HALF_UP); 
        // 解释:divide(除数, 保留小数位数, 舍入模式)
        // ROUND_HALF_UP:四舍五入
        System.out.println("商:" + div); // 输出:3.50
    }
}

DecimalFormat是java.text包下的类,专门用于将数字(整数、浮点数)格式化为指定格式的字符串,支持千分位分隔、固定小数位、补 0 等需求。其核心是通过格式模式字符串定义输出格式。

  1. 格式模式符号说明 先明确几个常用的格式符号含义:

#:表示任意数字,不存在则不显示(例如格式#.##,数字 1.2 会显示为1.2,而非1.20); ,:千分位分隔符(每三位数字分隔,如 1234567 会显示为1,234,567); .:小数点分隔符,用于区分整数部分和小数部分; 0:表示数字,不存在则补 0(例如格式0.00,数字 1.2 会显示为1.20)。 2. 示例:格式化大额数字与固定小数位 代码示例:

import java.text.DecimalFormat;

public class Main2 { public static void main(String[] args) { // 定义格式:千分位分隔,保留4位小数 DecimalFormat decimalFormat = new DecimalFormat("###,###.0000"); // 格式化数字12553456.598795 System.out.println(decimalFormat.format(12553456.598795)); } } AI写代码 java 运行

输出结果: 12,553,456.5988

解析:

格式###,###.0000中,###,###表示整数部分每三位用逗号分隔(千分位); .0000表示小数部分固定保留 4 位,不足则补 0,超出则四舍五入(原数字小数位是598795,四舍五入后为5988)。 3. 更多格式化场景示例 除了示例中的格式,DecimalFormat还支持多种实用格式,举例如下:

public class DecimalFormatDemo { public static void main(String[] args) { // 1. 整数部分补0(如固定3位整数,不足补0) DecimalFormat df1 = new DecimalFormat("000"); System.out.println(df1.format(5)); // 输出:005

csharp 复制代码
    // 2. 保留2位小数,整数部分千分位
    DecimalFormat df2 = new DecimalFormat("###,###.00");
    System.out.println(df2.format(123456.7)); // 输出:123,456.70
    
    // 3. 百分比格式(数字×100后加%)
    DecimalFormat df3 = new DecimalFormat("0.00%");
    System.out.println(df3.format(0.356)); // 输出:35.60%
    
    // 4. 科学计数法(保留2位小数)
    DecimalFormat df4 = new DecimalFormat("0.00E0");
    System.out.println(df4.format(123456)); // 输出:1.23E5(即1.23×10^5)
}

} AI写代码 java 运行

核心总结:DecimalFormat的关键是通过格式模式字符串定义规则,其中#和0用于控制数字位数(0强制补 0,#不强制),,用于千分位,.用于分隔整数和小数部分。

二、BigDecimal:高精度数值计算类 float和double是 Java 中的基本浮点类型,但由于二进制存储的特性,它们无法精确表示所有十进制小数(例如0.1用 double 存储时实际是近似值),在金融、电商等对精度要求极高的场景中会导致误差(如金额计算错误)。

BigDecimal是java.math包下的类,支持任意精度的数值计算,完美解决浮点精度问题。

  1. 为什么需要 BigDecimal? 先看一个反例:用double计算 0.1+0.2 的结果:

System.out.println(0.1 + 0.2); // 输出:0.30000000000000004(存在精度误差) AI写代码 java 运行 这是因为0.1和0.2在二进制中无法精确表示,累加后误差被放大。而BigDecimal可以避免这种问题:

import java.math.BigDecimal;

public class BigDecimalDemo { public static void main(String[] args) { BigDecimal a = new BigDecimal("0.1"); BigDecimal b = new BigDecimal("0.2"); System.out.println(a.add(b)); // 输出:0.3(精确计算) } } AI写代码 java 运行 2. 基本用法:创建与运算 BigDecimal的创建和加法运算:

// 创建BigDecimal对象(注意:不推荐用double构造,原因见下文) BigDecimal bigDecimal = new BigDecimal(1.555555555555555); BigDecimal bigDecimal1 = new BigDecimal(2.999999999999); // 加法运算 System.out.println(bigDecimal.add(bigDecimal1)); AI写代码 java 运行 输出结果(可能存在误差): 4.555555555554555

这里有个坑:用double作为参数构造BigDecimal时,由于double本身的精度问题,BigDecimal会保留其近似值,导致计算结果仍有误差。推荐用String作为构造参数,确保精度:

// 正确写法:用String构造 BigDecimal a = new BigDecimal("1.555555555555555"); BigDecimal b = new BigDecimal("2.999999999999"); System.out.println(a.add(b)); // 输出:4.555555555554555(精确) AI写代码 java 运行 3. 常用运算方法 BigDecimal提供了丰富的运算方法,支持加减乘除等操作,注意运算后需用变量接收结果(BigDecimal是不可变类,运算不会修改原对象):

java 复制代码
public class BigDecimalOperation {
    public static void main(String[] args) {
        BigDecimal a = new BigDecimal("10.5");
        BigDecimal b = new BigDecimal("3");
        
        // 加法
        BigDecimal sum = a.add(b);
        System.out.println("和:" + sum); // 输出:13.5
        
        // 减法
        BigDecimal sub = a.subtract(b);
        System.out.println("差:" + sub); // 输出:7.5
        
        // 乘法
        BigDecimal mul = a.multiply(b);
        System.out.println("积:" + mul); // 输出:31.5
        
        // 除法(需指定保留小数位和舍入模式,避免除不尽报错)
        BigDecimal div = a.divide(b, 2, BigDecimal.ROUND_HALF_UP); 
        // 解释:divide(除数, 保留小数位数, 舍入模式)
        // ROUND_HALF_UP:四舍五入
        System.out.println("商:" + div); // 输出:3.50
    }
}

除法注意事项:当除数不能整除被除数时(如 10.5÷3=3.5,但若 10÷3 则是无限循环),必须指定保留小数位数和舍入模式,否则会抛出ArithmeticException。常用舍入模式:

ROUND_HALF_UP:四舍五入(最常用); ROUND_DOWN:直接舍去多余小数(截断); ROUND_UP:向上进 1(无论小数位是否大于 0)。

三、注意事项与最佳实践

1. DecimalFormat 的线程安全性

DecimalFormat是非线程安全的(内部有可变状态),多线程环境下若共享同一个DecimalFormat实例,可能导致格式化结果错乱。解决方式:

  1. 每个线程创建独立的DecimalFormat实例;
  2. 用ThreadLocal封装,确保线程私有。

2. BigDecimal 的构造方法选择

尽量避免用double构造BigDecimal(如new BigDecimal(0.1)),因为double本身精度有误差。推荐用String构造(new BigDecimal("0.1")),或使用BigDecimal.valueOf(double)(内部会先转为 String,减少误差)。

3. BigDecimal 的比较大小

不能用==equals()比较BigDecimal的值(equals()会同时比较值和精度,如new BigDecimal("1.0").equals(new BigDecimal("1"))返回false)。正确方式是用compareTo:

java 复制代码
BigDecimal x = new BigDecimal("1.0");
BigDecimal y = new BigDecimal("1");
System.out.println(x.compareTo(y) == 0); // 输出:true(表示相等)
// compareTo返回值:0(相等)、1(x>y)、-1(x<y)

4. 适用场景区分

  • DecimalFormat:用于数字的格式化展示(如界面显示金额、报表数据);
  • BigDecimal:用于高精度数值计算(如金融交易、金额累加、税率计算)。
相关推荐
郭钊荣2 小时前
为什么 OpenClaw 能出圈:扒一扒小龙虾的agent系统设计
后端·github
Nyarlathotep01132 小时前
gin02:gin路径中的参数
后端·go
beata2 小时前
Java基础-16:Java内置锁的四种状态及其转换机制详解-从无锁到重量级锁的进化与优化指南
java·后端
Mintopia2 小时前
软件系统中的订单-审核业务架构分析与实践
后端·架构
IT探险家2 小时前
你的第一个 Java 程序就翻车?HelloWorld 的 8 个隐藏陷阱
java
茶杯梦轩2 小时前
从零起步学习RabbitMQ || 第二章:RabbitMQ 深入理解概念 Producer、Consumer、Exchange、Queue 与企业实战案例
服务器·后端·消息队列
随风飘的云2 小时前
SpringBoot 的自动配置原理
java
随逸1772 小时前
《 吃透RAG:从原理到LangChain实战,彻底解决大模型幻觉问题》
后端
SimonKing2 小时前
觅得又一款轻量级数据库管理工具:GoNavi
java·后端·程序员