当前位置: 首页 > news >正文

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

目录

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

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

实战示例:Date 类基础使用

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

1.2.1 创建 LocalDateTime 对象

1.2.2 获取日期时间字段

1.2.3 日期时间运算:增减时间

1.2.4 日期时间调整:获取特殊时间

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

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

2.2 基础运算:加、减、乘

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

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

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 类基础使用
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 对象

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类更直观。

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

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()(减少时间)方法,支持天、周、月、年、时、分、秒等维度的运算,方法返回新对象(原对象不可变),使用时需接收返回值。

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

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()方法,可快速获取本周周一 / 周日、本月第一天 / 最后一天、本年第一天 / 最后一天等特殊时间,无需手动计算,简化开发。

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

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转为字符串,避免精度丢失)。

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

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 加减乘运算

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 除法运算

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 开发的基础且核心的工具,掌握其正确用法能有效避免开发中的常见坑(如日期偏移、精度丢失),提升代码的健壮性和可维护性。

http://www.jsqmd.com/news/513282/

相关文章:

  • 永磁直驱式风电虚拟同步机仿真模型,风力发电虚拟同步机控制matlab仿真,风电VSG仿真
  • 快速上手!Qwen2.5-0.5B-Instruct网页推理服务实战体验
  • 通义千问1.5-1.8B-Chat-GPTQ-Int4集成Dify实战:快速构建可视化AI应用
  • 2026防水补漏公司哪家靠谱?行业口碑机构推荐 - 品牌排行榜
  • Qwen3-32B-Chat RTX4090D部署教程:模型加载时OOM错误定位与修复
  • QwQ-32B开源大模型ollama实战:构建自主思考型AI客服原型
  • Win10搭建NFS服务器踩坑实录:从安装包选择、配置语法到防火墙设置的全流程避坑指南
  • 专利撰写辅助工具:DeepSeek-R1法律文本推理尝试
  • 转子动力学中的临界转速计算:Workbench建模与模态振型及坎贝尔图解析
  • Qwen3-32B-Chat效果实测:中英混合输入下的语义连贯性与专业术语准确性
  • ERNIE-4.5-0.3B-PT效果实测:Chainlit中软件需求文档自动生成与UML推导
  • OpenClaw+QwQ-32B:个人健康管理助手实战
  • 开发者必备:OpenClaw对接Qwen3-32B实现日志分析与错误排查
  • N5110驱动库实现像素级坐标文本渲染
  • 基于非线性干扰观测器的自适应滑模反演控制:机械臂模型的 Matlab 仿真探索
  • Youtu-Parsing模型Java后端集成指南:SpringBoot微服务开发
  • 万物识别-中文镜像真实案例:校园场景课桌物品识别与学习行为分析图谱
  • Flutter气泡框进阶:动态调整与圆角优化
  • Stable-Diffusion-V1-5 开发利器:ChatGPT辅助编写模型调用与图像处理脚本
  • LiuJuan20260223Zimage开源协作工具链:GitHub Actions自动构建+OSS镜像同步+Telegram通知
  • NAS新手教程:D-Link DNS-320与Time Machine的完美搭配(避坑指南)
  • LC-3模拟器安装到调试全指南:Windows/Mac双平台配置教程
  • NEC红外接收模块软硬件设计与解码实现
  • 影墨·今颜小红书风格AI绘画一键部署:Python环境配置与模型调用实战
  • AI净界RMBG-1.4实战案例:一张图搞定电商、设计、教学三种需求
  • 嵌入式开发新纪元:Janus-Pro-7B实践
  • 折腾Rsoft能带图的三两事
  • Qwen3-0.6B-FP8政务场景:基层办事指南AI问答终端边缘部署案例
  • 实时语音识别与语音转文本技术:WhisperLive全方位实践指南
  • 告别依赖冲突!用Gradle Dependency Graph插件生成酷炫依赖关系图(附2023最新配置)