Java入门( 日期类与 BigDecimal 工具类 )

目录

[一、日期时间处理类:从 Date 到 LocalDateTime 的升级](#一、日期时间处理类:从 Date 到 LocalDateTime 的升级)

[1.1 老牌 Date 类:了解即可,慎用为主](#1.1 老牌 Date 类:了解即可,慎用为主)

[实战示例:Date 类基础使用](#实战示例:Date 类基础使用)

[1.2 LocalDateTime 类:Java8 + 日期处理首选](#1.2 LocalDateTime 类:Java8 + 日期处理首选)

[1.2.1 创建 LocalDateTime 对象](#1.2.1 创建 LocalDateTime 对象)

[1.2.2 获取日期时间字段](#1.2.2 获取日期时间字段)

[1.2.3 日期时间运算:增减时间](#1.2.3 日期时间运算:增减时间)

[1.2.4 日期时间调整:获取特殊时间](#1.2.4 日期时间调整:获取特殊时间)

[二、BigDecimal 类:高精度数值运算的救星](#二、BigDecimal 类:高精度数值运算的救星)

[2.1 核心注意点:创建 BigDecimal 对象的正确方式](#2.1 核心注意点:创建 BigDecimal 对象的正确方式)

[2.2 基础运算:加、减、乘](#2.2 基础运算:加、减、乘)

[2.3 除法运算:解决无限循环小数问题](#2.3 除法运算:解决无限循环小数问题)

[2.3.1 舍入模式:8 种核心规则](#2.3.1 舍入模式:8 种核心规则)

[2.3.2 除法实战:指定精度 + 舍入模式](#2.3.2 除法实战:指定精度 + 舍入模式)

三、核心总结


在 Java 日常开发中,处理日期时间和高精度数值运算是高频需求,早期的Date类存在方法过时、设计不友好等问题,而浮点型double/float的精度丢失问题更是让财务、金融等场景的运算避之不及。本文将详细讲解 Java 中日期时间处理Date类、LocalDateTime类)和高精度数值运算BigDecimal类)的核心用法,结合实战示例拆解关键知识点,帮你彻底掌握这两个开发必备工具类。

一、日期时间处理类:从 Date 到 LocalDateTime 的升级

日期时间处理是开发中不可或缺的部分,Java 从最初的Date类,到 Java 8 引入的java.time包下的LocalDateTime类,实现了从 "简陋" 到 "优雅" 的跨越。LocalDateTime解决了Date类线程不安全、方法过时、时区处理繁琐等问题,成为目前主流的日期时间处理方案。

1.1 老牌 Date 类:了解即可,慎用为主

Date类位于java.util包,用于表示精确到毫秒的日期时间,但其大部分构造方法和成员方法已被标记为过时,仅作兼容旧代码使用,核心特点和注意事项如下:

  1. 无参构造方法new Date()获取当前系统时间
  2. 带年 / 月 / 日参数的构造方法存在偏移问题:年份从 1900 开始计算,月份 0 代表 1 月、1 代表 2 月,以此类推;
  3. 多数获取时间字段的方法(如getHours()getMonth())已被Calendar类替代,仅保留after()before()compareTo()等少数比较方法。
实战示例:Date 类基础使用
java 复制代码
import java.util.Date;

public class DateDemo {
    public static void main(String[] args) {
        // 1. 获取当前系统时间,精确到毫秒
        Date nowDate = new Date();
        System.out.println("当前系统时间:" + nowDate);

        // 2. 构造指定时间(注意偏移:124=2024-1900,1=2月,10=10日)
        Date specifyDate = new Date(124, 1, 10, 15, 30, 20);
        System.out.println("指定时间(2024-02-10 15:30:20):" + specifyDate);

        // 3. 日期比较:after/before/compareTo
        boolean isAfter = nowDate.after(specifyDate);
        boolean isBefore = nowDate.before(specifyDate);
        int compare = nowDate.compareTo(specifyDate);
        System.out.println("当前时间是否在指定时间之后:" + isAfter);
        System.out.println("当前时间是否在指定时间之前:" + isBefore);
        System.out.println("日期比较结果(0=相等,1=大于,-1=小于):" + compare);
    }
}

输出结果(随系统时间变化):

复制代码
当前系统时间:Sat Mar 21 16:00:00 CST 2026
指定时间(2024-02-10 15:30:20):Sat Feb 10 15:30:20 CST 2024
当前时间是否在指定时间之后:true
当前时间是否在指定时间之前:false
日期比较结果(0=相等,1=大于,-1=小于):1

1.2 LocalDateTime 类:Java8 + 日期处理首选

LocalDateTime位于java.time包,是不可变、线程安全 的日期时间类,整合了LocalDate(日期)和LocalTime(时间),支持日期时间的创建、解析、字段获取、运算、调整等所有常用操作,是目前 Java 开发中日期时间处理的核心类

1.2.1 创建 LocalDateTime 对象

LocalDateTime的构造方法为私有,无法直接new,需通过静态方法 创建,核心方式有 3 种:获取当前时间、指定日期时间、从字符串解析,其中字符串解析需配合DateTimeFormatter指定格式(注意大小写yyyy= 年,MM= 月,dd= 日,HH=24 小时制,hh=12 小时制)。

实战示例:创建 LocalDateTime 对象

java 复制代码
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class LocalDateTimeCreate {
    public static void main(String[] args) {
        // 方式1:获取当前系统日期时间(最常用)
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前日期时间:" + now);

        // 方式2:指定年/月/日/时/分/秒创建
        LocalDateTime specifyTime = LocalDateTime.of(2026, 3, 21, 16, 0, 0);
        System.out.println("指定日期时间:" + specifyTime);

        // 方式3:从自定义格式的字符串解析(需指定DateTimeFormatter)
        String timeStr = "2026-03-21 16:05:30";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime parseTime = LocalDateTime.parse(timeStr, formatter);
        System.out.println("字符串解析的日期时间:" + parseTime);
    }
}

输出结果

复制代码
当前日期时间:2026-03-21T16:00:00.123456789
指定日期时间:2026-03-21T16:00
字符串解析的日期时间:2026-03-21T16:05:30
1.2.2 获取日期时间字段

通过getXxx()系列方法可直接获取年、月、日、时、分、秒、星期、年内天数等字段,无偏移问题 ,比Date类更直观。

实战示例:获取日期时间字段

java 复制代码
import java.time.LocalDateTime;

public class LocalDateTimeGet {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        // 基础字段:年、月、日、时、分、秒
        int year = now.getYear();
        int month = now.getMonthValue(); // 获取数字月份(1-12)
        int day = now.getDayOfMonth();
        int hour = now.getHour();
        int minute = now.getMinute();
        int second = now.getSecond();

        // 扩展字段:星期、本月天数、年内天数
        int week = now.getDayOfWeek().getValue(); // 星期(1=周一,7=周日)
        int dayOfYear = now.getDayOfYear();

        // 打印结果
        System.out.println("年:" + year + " 月:" + month + " 日:" + day);
        System.out.println("时:" + hour + " 分:" + minute + " 秒:" + second);
        System.out.println("本周星期:" + week + " 当年第" + dayOfYear + "天");
    }
}

输出结果

复制代码
年:2026 月:3 日:21
时:16 分:10 秒:25
本周星期:6 当年第80天
1.2.3 日期时间运算:增减时间

LocalDateTime提供plusXxx()(增加时间)和minusXxx()(减少时间)方法,支持天、周、月、年、时、分、秒等维度的运算,方法返回新对象(原对象不可变),使用时需接收返回值。

实战示例:日期时间增减运算

java 复制代码
import java.time.LocalDateTime;

public class LocalDateTimeCalculate {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        System.out.println("原始时间:" + now);

        // 增加时间:1天、2周、3个月、1年、2小时
        LocalDateTime plusTime = now.plusDays(1).plusWeeks(2).plusMonths(3).plusYears(1).plusHours(2);
        System.out.println("增加后时间:" + plusTime);

        // 减少时间:3天、1周、2个月、10小时
        LocalDateTime minusTime = now.minusDays(3).minusWeeks(1).minusMonths(2).minusHours(10);
        System.out.println("减少后时间:" + minusTime);
    }
}

输出结果

复制代码
原始时间:2026-03-21T16:15:30.123
增加后时间:2027-06-05T18:15:30.123
减少后时间:2026-01-15T06:15:30.123
1.2.4 日期时间调整:获取特殊时间

通过TemporalAdjusters工具类配合with()方法,可快速获取本周周一 / 周日、本月第一天 / 最后一天、本年第一天 / 最后一天等特殊时间,无需手动计算,简化开发。

实战示例:获取特殊日期时间

java 复制代码
import java.time.LocalDateTime;
import java.time.DayOfWeek;
import java.time.temporal.TemporalAdjusters;

public class LocalDateTimeAdjust {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前时间:" + now);

        // 1. 本周周一和周日(previousOrSame/nextOrSame:当前或最近的指定星期)
        LocalDateTime monday = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDateTime sunday = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
        // 2. 本月第一天和最后一天
        LocalDateTime firstDayOfMonth = now.with(TemporalAdjusters.firstDayOfMonth());
        LocalDateTime lastDayOfMonth = now.with(TemporalAdjusters.lastDayOfMonth());
        // 3. 本年第一天和最后一天
        LocalDateTime firstDayOfYear = now.with(TemporalAdjusters.firstDayOfYear());
        LocalDateTime lastDayOfYear = now.with(TemporalAdjusters.lastDayOfYear());

        // 打印结果
        System.out.println("本周周一:" + monday);
        System.out.println("本周周日:" + sunday);
        System.out.println("本月第一天:" + firstDayOfMonth);
        System.out.println("本月最后一天:" + lastDayOfMonth);
        System.out.println("本年第一天:" + firstDayOfYear);
        System.out.println("本年最后一天:" + lastDayOfYear);
    }
}

输出结果

复制代码
当前时间:2026-03-21T16:20:00.123
本周周一:2026-03-17T16:20:00.123
本周周日:2026-03-23T16:20:00.123
本月第一天:2026-03-01T16:20:00.123
本月最后一天:2026-03-31T16:20:00.123
本年第一天:2026-01-01T16:20:00.123
本年最后一天:2026-12-31T16:20:00.123

二、BigDecimal 类:高精度数值运算的救星

在处理金额、税率、汇率等高精度数值运算时,doublefloat会因二进制存储的精度丢失问题 导致计算结果错误(例如0.1+0.2=0.30000000000000004)。BigDecimal类位于java.math包,是不可变、线程安全的高精度数值类,支持任意精度的小数运算,完美解决浮点型精度问题。

2.1 核心注意点:创建 BigDecimal 对象的正确方式

BigDecimal提供了多种构造方法,其中 **double构造方法存在精度丢失风险 **,字符串构造方法是推荐方式 (可精确表示数值)。如果必须使用double创建,可通过BigDecimal.valueOf(double val)静态方法(内部将double转为字符串,避免精度丢失)。

实战示例:不同构造方法的对比

java 复制代码
import java.math.BigDecimal;

public class BigDecimalCreate {
    public static void main(String[] args) {
        // 错误方式:double构造方法,精度丢失
        BigDecimal bigDecimalDouble = new BigDecimal(0.1);
        // 正确方式1:字符串构造方法,精确表示
        BigDecimal bigDecimalStr = new BigDecimal("0.1");
        // 正确方式2:valueOf静态方法,处理double类型
        BigDecimal bigDecimalValueOf = BigDecimal.valueOf(0.1);

        // 打印结果对比
        System.out.println("double构造方法:" + bigDecimalDouble);
        System.out.println("字符串构造方法:" + bigDecimalStr);
        System.out.println("valueOf静态方法:" + bigDecimalValueOf);
    }
}

输出结果

复制代码
double构造方法:0.1000000000000000055511151231257827021181583404541015625
字符串构造方法:0.1
valueOf静态方法:0.1

2.2 基础运算:加、减、乘

BigDecimal的加减乘运算通过add()subtract()multiply()方法实现,所有方法均返回新的 BigDecimal 对象 (原对象不可变),运算时需保证操作数均为BigDecimal类型,且通过字符串构造创建。

实战示例:BigDecimal 加减乘运算

java 复制代码
import java.math.BigDecimal;

public class BigDecimalAddSubMul {
    public static void main(String[] args) {
        // 初始化两个高精度数值(金额:100.50 元和 25.30 元)
        BigDecimal num1 = new BigDecimal("100.50");
        BigDecimal num2 = new BigDecimal("25.30");

        // 加法:100.50 + 25.30
        BigDecimal addResult = num1.add(num2);
        // 减法:100.50 - 25.30
        BigDecimal subResult = num1.subtract(num2);
        // 乘法:100.50 * 25.30
        BigDecimal mulResult = num1.multiply(num2);

        // 打印结果
        System.out.println("加法结果:" + addResult + " 元");
        System.out.println("减法结果:" + subResult + " 元");
        System.out.println("乘法结果:" + mulResult + " 元");
    }
}

输出结果

复制代码
加法结果:125.80 元
减法结果:75.20 元
乘法结果:2542.6500 元

2.3 除法运算:解决无限循环小数问题

BigDecimal的除法运算通过divide()方法实现,如果运算结果为无限循环小数,直接调用无参 divide () 会抛出 ArithmeticException 异常 ,因此实际开发中必须指定精度和舍入模式 ,或通过MathContext指定运算规则。

2.3.1 舍入模式:8 种核心规则

Java 提供RoundingMode枚举类定义了 8 种舍入模式,开发中最常用的是 **HALF_UP(四舍五入)**,其他模式可根据业务场景选择(如财务结算的HALF_EVEN银行家舍入法),核心模式说明如下:

舍入模式 核心规则 示例
UP 远离零舍入 1.234→1.24,-1.234→-1.24
DOWN 接近零舍入 1.236→1.23,-1.236→-1.23
HALF_UP 四舍五入 1.235→1.24,-1.235→-1.24
HALF_EVEN 银行家舍入(奇数进,偶数舍) 1.235→1.24,1.245→1.24
UNNECESSARY 断言精确结果,否则抛异常 10/2=5(正常),1/3(抛异常)
2.3.2 除法实战:指定精度 + 舍入模式

推荐方式divide(BigDecimal divisor, int scale, RoundingMode roundingMode),其中scale为保留的小数位数,roundingMode为舍入模式。

实战示例:BigDecimal 除法运算

java 复制代码
import java.math.BigDecimal;
import java.math.RoundingMode;

public class BigDecimalDivide {
    public static void main(String[] args) {
        // 初始化数值:10.0 除以 3.0(无限循环小数)
        BigDecimal num1 = new BigDecimal("10.0");
        BigDecimal num2 = new BigDecimal("3.0");

        // 方式1:指定精度(保留2位小数)+ 四舍五入模式(最常用)
        BigDecimal divide1 = num1.divide(num2, 2, RoundingMode.HALF_UP);
        // 方式2:指定精度(保留3位小数)+ 银行家舍入法
        BigDecimal divide2 = num1.divide(num2, 3, RoundingMode.HALF_EVEN);
        // 方式3:通过MathContext指定精度和模式(总精度4位,四舍五入)
        BigDecimal divide3 = num1.divide(num2, new java.math.MathContext(4, RoundingMode.HALF_UP));

        // 打印结果
        System.out.println("10.0/3.0(保留2位,四舍五入):" + divide1);
        System.out.println("10.0/3.0(保留3位,银行家舍入):" + divide2);
        System.out.println("10.0/3.0(总精度4位,四舍五入):" + divide3);
    }
}

输出结果

复制代码
10.0/3.0(保留2位,四舍五入):3.33
10.0/3.0(保留3位,银行家舍入):3.333
10.0/3.0(总精度4位,四舍五入):3.333

三、核心总结

  1. 日期时间处理 :优先使用 Java8 + 的LocalDateTime,摒弃过时的Date类;LocalDateTime支持创建、解析、字段获取、运算、调整等所有操作,线程安全且无偏移问题,配合DateTimeFormatter处理字符串解析,TemporalAdjusters处理特殊时间。
  2. 高精度数值运算 :使用BigDecimal替代double/float,避免精度丢失;必须通过字符串构造方法或valueOf()创建对象 ,运算后接收新返回对象,除法运算需指定精度和舍入模式,常用HALF_UP(四舍五入)。
  3. 共性特点LocalDateTimeBigDecimal均为不可变类,所有修改 / 运算方法均返回新对象,原对象保持不变,天生线程安全,适合高并发场景。

这两个工具类是 Java 开发的基础且核心的工具,掌握其正确用法能有效避免开发中的常见坑(如日期偏移、精度丢失),提升代码的健壮性和可维护性。

相关推荐
Lhan.zzZ2 小时前
深入浅出 Qt 信号槽连接方式:从 AutoConnection 到 BlockingQueuedConnectionQt
开发语言·c++·qt
好好学习叭~2 小时前
正则表达式
java·开发语言
William_cl2 小时前
C# ASP.NET Identity 授权实战:[Authorize (Roles=“Admin“)] 仅管理员访问(避坑 + 图解)
开发语言·c#·asp.net
草莓熊Lotso2 小时前
MySQL 内置函数指南:日期、字符串、数学函数实战
android·java·linux·运维·数据库·c++·mysql
ab1515172 小时前
3.21二刷基础125、122、130,完成进阶65
开发语言·c++·算法
for_ever_love__2 小时前
Objective-C学习 NSDictionary,NSMutableDictionary 功能详解
开发语言·学习·ios·objective-c
for_ever_love__2 小时前
Objective-C学习 协议和委托
开发语言·学习·ios·objective-c
计算机学姐2 小时前
基于SpringBoot的蛋糕烘焙销售服务系统
java·spring boot·后端·spring·tomcat·intellij-idea·mybatis
lars_lhuan2 小时前
Go Once
开发语言·golang