日期相关类
Date 类
java.util.Date:Java 早期的日期时间类,精确到毫秒,用来表示一个特定的时刻- 常用成员方法
可用方法:
1)boolean after(Date when):判断当前日期是否在指定日期之后
2)boolean before(Date when):判断当前日期是否在指定日期之前
3)int compareTo(Date anotherDate):比较两个 Date,返回正负 / 0
4)boolean equals(Object obj):比较两个时间是否相等
5)static Date from(Instant instant):Instant 转 Date
LocalDateTime
LocalDateTime是Java 8引入的日期时间类,不可变类,
没有时区信息,只保存日期 + 时间(年、月、日、时、分、秒)- 构造方法是
private私有,不能直接new创建对象,只能通过静态方法获取实例//私有构造 private LocalDateTime(LocalDate date, LocalTime time) { this.date = date; this.time = time; }创建 LocalDateTime 对象
//1. 获取当前系统日期时间 LocalDateTime now = LocalDateTime.now(); //2. 指定年月日时分,创建时间 LocalDateTime dateTime = LocalDateTime.of(2023, 5, 15, 10, 30); //3. 解析字符串(默认格式:yyyy-MM-ddTHH:mm:ss) LocalDateTime parsed = LocalDateTime.parse("2023-05-15T10:30:00");//1.1 获取当前日期时间 LocalDateTime now= LocalDateTime.now(); System.out.println("当前日期 now(): "+now); // 1.2 指定年月日时分创建 LocalDateTime dateTimeOf=LocalDateTime.of(2026,10,11,13,56,30); System.out.println("of指定时间:"+dateTimeOf); // 1.3 默认格式字符串解析 LocalDateTime parsedDefault=LocalDateTime.parse("2026-10-11T13:56:20"); System.out.println("默认parse解析:"+parsedDefault);
获取当前日期时间
//1.1 获取当前日期时间 LocalDateTime now= LocalDateTime.now(); System.out.println("当前日期 now(): "+now);获取 年、月、日、时、分、秒
LocalDateTime dateTime=LocalDateTime.now(); int year=dateTime.getYear(); int month=dateTime.getMonthValue(); int day=dateTime.getDayOfMonth(); int hour=dateTime.getHour(); int minute=dateTime.getMinute(); int second=dateTime.getSecond(); System.out.println("年:"+year); System.out.println("月:"+month); System.out.println("日:"+day); System.out.println("时:"+hour); System.out.println("分:"+minute); System.out.println("秒:"+second);
创建指定日期时间 of ()
// 1.2 指定年月日时分创建 LocalDateTime dateTimeOf=LocalDateTime.of(2026,10,11,13,56,30); System.out.println("of指定时间:"+dateTimeOf);
自定义字符串解析
parse + DateTimeFormatter
yyyy:4 位年份
MM:2 位月份
dd:2 位日期
HH:24 小时制小时
mm:分钟
ss:秒
String stringDate="2026-10-11 14:20:32"; DateTimeFormatter dateTimeFormatter= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime parseTime=LocalDateTime.parse(stringDate,dateTimeFormatter); System.out.println("自定义格式解析结果:"+parseTime);
获取详细时间信息
System.out.println("当前日期为:"+dateTime); System.out.println("本周周几(1==周一,7==周日):"+dateTime.getDayOfWeek().getValue()); System.out.println("本月第几天:"+dateTime.getDayOfMonth()); System.out.println("当年第几天:"+dateTime.getDayOfYear());
日期运算
(plusXXX /minusXXX)
LocalDateTime不可变,调用 plus/minus 方法会返回新对象,原对象不会修改
plusDays(1)加 1 天minusDays(1)减 1 天plusWeeks(1)加 1 周minusWeeks(1)减 1 周plusMonths(1)加 1 月minusMonths(1)减 1 月plusYears(1)加 1 年minusYears(1)减 1 年
// 增减天数 LocalDateTime plus1Day=dateTime.plusDays(1); LocalDateTime minus1Day=dateTime.minusDays(1); System.out.println("增加1天后:"+plus1Day); System.out.println("减少1天后:"+minus1Day); //增减周 LocalDateTime plus1Week=dateTime.plusWeeks(1); LocalDateTime minus1Week=dateTime.minusWeeks(1); System.out.println("增加一周后:"+plus1Week); System.out.println("减少一周后:"+minus1Week); //增减月 LocalDateTime plus1Month=dateTime.plusMonths(1); LocalDateTime minus1Month=dateTime.minusMonths(1); System.out.println("增加一月后:"+plus1Month); System.out.println("减少一月后:"+minus1Month); //增减年 LocalDateTime plus1Year=dateTime.plusYears(1); LocalDateTime minus1Year=dateTime.minusYears(1); System.out.println("增加一年后:"+plus1Year); System.out.println("减少一年后:"+minus1Year);
TemporalAdjusters 时间调节器(获取指定时间)
获取本周周一、周日
LocalDateTime currentDate=LocalDateTime.now(); //previousOrSame :当前或之前最近的周一 LocalDateTime firstDayOfWeek=currentDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); //nextOrSame:当前或之后最近的周日 LocalDateTime lastDayOfWeek=currentDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)); System.out.println("本周周一:"+firstDayOfWeek); System.out.println("本周周日:"+lastDayOfWeek);
previousOrSame:寻找当前日期或之前最近的指定星期nextOrSame:寻找当前日期或之后最近的指定星期获取当月第一天、当月最后一天
LocalDateTime currentDate1=LocalDateTime.now(); LocalDateTime firstDayOfMonth=currentDate1.with(TemporalAdjusters.firstDayOfMonth()); LocalDateTime lastDayOfMonth=currentDate1.with(TemporalAdjusters.lastDayOfMonth()); System.out.println("当月第一天:"+firstDayOfMonth); System.out.println("当月最后一天:"+lastDayOfMonth);
总结
- 不可变:每次修改时间都会生成新对象,原对象不变
- 私有构造:不能 new,只能
now()/of()/parse()创建- 格式化:
DateTimeFormatter线程安全,替代旧SimpleDateFormat- 时间调节器 TemporalAdjusters:快速获取月初、月末、周起始等特殊时间
- 旧
Date、Calendar线程不安全,新项目优先使用 Java8 时间 API
BigDecimal
BigDecimal在java.math包,用于高精度数值运算,解决 float/double 浮点丢失精度的问题(double 只能保证 16 位有效数字)- BigDecimal 是不可变类,每次加减乘除都会返回新的 BigDecimal 对象,原对象不会变
构造方法
原理//传入double 1.99 double 存储不精确 BigDecimal doubleNum=new BigDecimal(1.99); System.out.println(doubleNum); // 1.98999999 //传入字符串 "2.99" 直接精确解析 BigDecimal stringNum=new BigDecimal("2.99"); System.out.println(stringNum); // 2.99
new BigDecimal(1.99):
a)代码里的1.99是 double 字面量,
double 底层二进制无法精确表示十进制小数,存的是一个近似值
b)BigDecimal 只是把这个已经不准确的 double 值完整精确还原出来,
所以输出一长串小数- 开发规范:
1)不要用 BigDecimal (double) 构造器,
优先使用字符串构造器new BigDecimal("数字")
2)如果已经有 double 变量,可以用BigDecimal.valueOf(double值),
底层会转字符串,避免精度丢失- 比较大小
1)不要用==、不要直接用equals()
2)equals():会同时比较数值 + 小数位数,new BigDecimal("2.0")和new BigDecimal("2")equals 判断不相等
3)compareTo(),可以用这个比较BigDecimal num1=new BigDecimal("10.0"); BigDecimal num2=new BigDecimal("10"); System.out.println(num1.compareTo(num2)); //返回 0 代表相等,大于0代表num1>num2,小于0代表num1<num2- 常见使用场景
金额计算(支付、财务)、科学计算,所有要求不能丢失小数精度的场景- 面试考点总结
1)为什么不用 double 做金额?二进制浮点无法精确表示部分十进制小数,
存在精度丢失
2)BigDecimal 构造器,BigDecimal(double)的坑
3)BigDecimal 是不可变类,运算会产生新对象
3)比较数值用compareTo,不要 equals
4)除法必须指定舍入规则,防止除不尽报错BigDecimal 加减乘方法
BigDecimal a=new BigDecimal("1.35"); BigDecimal b=new BigDecimal("3.22"); //加法 add() BigDecimal addRet=a.add(b); System.out.println(addRet); // 4.57 // 减法 subtract() BigDecimal subRet=a.subtract(b); System.out.println(subRet); //-1.87 // 乘法 multiply() BigDecimal mulRet=a.multiply(b); System.out.println(mulRet); // 4.3470- 核心重点
1)BigDecimal 是不可变类
2)a.add(b)不是修改对象a的值,会返回一个全新 BigDecimal 对象,
原来的a、b保持不变- 三个方法说明
BigDecimal divide () 除法
报错代码(错误写法)
BigDecimal a=new BigDecimal("1.35"); BigDecimal b=new BigDecimal("3.22"); BigDecimal divRet=a.divide(b); System.out.println(divRet);
报错原因
a.divide(b) 不带保留位数参数时,要求除法结果必须是有限小数- 方案一:指定小数位数 + 舍入模式(最常用)
BigDecimal a=new BigDecimal("1.35"); BigDecimal b=new BigDecimal("3.22"); //参数1:除数 参数2:保留小数位数 参数3 : 舍入模式 BigDecimal divRet=a.divide(b,4, RoundingMode.HALF_DOWN); System.out.println(divRet);1)4:结果保留4 位小数
2)RoundingMode.HALF_UP:四舍五入,0.5 向上进 1(财务开发最常用)
3)注意:除法顺序:a.divide(b) 代表 a ÷ b- 全部舍入模式对照表
面试重点:银行家舍入 HALF_EVEN,很多框架默认用这个,不是传统四舍五入- 方案二:MathContext 方式
BigDecimal a=new BigDecimal("1.35"); BigDecimal b=new BigDecimal("3.22"); // MathContext第一个参数是 [有效数字位数] 不是小数位数 BigDecimal divRet=a.divide(b,new MathContext(4,RoundingMode.HALF_UP)); // 0.4193 System.out.println(divRet);区分重点:
1)divide(b, 4, HALF_UP):保留 4 位小数(scale=4)
2)MathContext(4,HALF_UP):总共保留 4 位有效数字(precision=4)
例:123.45,保留 4 位有效数字 →123.5,和小数位数不是一回事- 除法核心总结
1)写 BigDecimal 除法严禁直接写a.divide(b),无限小数直接抛异常
2)业务开发(金额计算)优先用三参数divide
(除数,保留小数位数, RoundingMode.HALF_UP)
3)分清「小数位数 scale」和「有效数字 precision」
4)BigDecimal 不可变,除法返回新对象,原对象不变
BigDecimal 比较:compareTo()
面试高频考点:不要用
==,不要直接用equals(),优先使用compareTo()- 错误示例
1)例1 equals() 同时比较【数值 + 小数位数(scale)】原因:BigDecimal num1=new BigDecimal("2.0"); BigDecimal num2=new BigDecimal("2"); System.out.println(num1.equals(num2)); // falsea)num1的值是2.0,scale=1(1 位小数)b)num2的值是2,scale=0(0 位小数)c)equals会把数字大小和小数位数一起对比,虽然数值相等,
但小数位数不一样,返回 false
2)例2 == 比较对象地址==判断是不是同一个对象,不是比较数值,基本永远不适合 BigDecimal 数值对比- 正确方法:compareTo()
BigDecimal num1 = new BigDecimal("2.0"); BigDecimal num2 = new BigDecimal("2"); BigDecimal num3=new BigDecimal("3"); int result=num1.compareTo(num2); // 0 System.out.println(result); System.out.println(num1.compareTo(num3)); // -1 num1 < num3 System.out.println(num3.compareTo(num1)); // 1 num3 > num1 System.out.println(num1.compareTo(num2)); // 0 num1==num2返回值规则:
a)result == 0→两个数字大小相等(忽略小数位数)b)result > 0→num1 > num2c)result < 0→num1 < num2- 业务常用封装写法
BigDecimal a=new BigDecimal("10.0"); BigDecimal b=new BigDecimal("5"); if(a.compareTo(b)>0) { System.out.println("a大于b"); } else if(a.compareTo(b)<0) { System.out.println("a小于b"); } else { System.out.println("a等于b"); }- 拓展小知识点:BigDecimal.ZERO
开发中经常和 0 比较,推荐用常量:BigDecimal money = new BigDecimal("0.00"); if(money.compareTo(BigDecimal.ZERO) == 0){ System.out.println("金额等于0"); }内置常量还有:
a)BigDecimal.ZERO0b)BigDecimal.ONE1c)BigDecimal.TEN10- 总结
1)equals()比较数值 + 小数位数;2)compareTo()只比较数值大小,业务开发比较 BigDecimal 数值必须用compareTo()