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:用于高精度数值计算(如金融交易、金额累加、税率计算)。
相关推荐
长栎34 分钟前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode37 分钟前
Redis 在生产项目的使用
前端·后端
用户5598224812242 分钟前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode43 分钟前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战44 分钟前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
xiaodaoluanzha1 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn1 小时前
Docker 容器管理入门 — 从镜像到容器编排
后端
用户762352425911 小时前
ShardingJDBC
后端
行者全栈架构师1 小时前
IDEA 中 Maven 项目的 15 个红色报错快速解决方法
java·后端
令人头秃的代码0_01 小时前
mac(m5)平台编译openjdk
java