方法定义
LocalDate.with()
是 java.time.LocalDate
类中用于创建修改后的新日期对象的一组方法。由于 LocalDate
是不可变对象,with
方法不会修改原对象,而是返回一个新的 LocalDate
实例。
主要重载方法
// 1. 使用 TemporalAdjuster(调整器)
public LocalDate with(TemporalAdjuster adjuster)
// 2. 修改指定字段
public LocalDate with(TemporalField field, long newValue)
功能说明
with()
方法的核心功能是 “基于当前日期,生成一个修改了某些字段的新日期”。它是函数式编程中“不可变性”原则的体现。
两大使用方向:
- 字段级修改:直接设置年、月、日等具体值。
- 逻辑级调整:使用预定义或自定义的“调整器”实现复杂日期计算(如“下一个周日”、“本月最后一天”)。
示例代码
方向一:字段级修改(with(TemporalField, long)
)
import java.time.LocalDate;
import java.time.temporal.ChronoField;
public class WithFieldExample {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2025, 8, 15); // 2025-08-15
System.out.println("原始日期: " + date);
// 修改年份
LocalDate newYear = date.with(ChronoField.YEAR, 2030);
System.out.println("修改年份: " + newYear); // 2030-08-15
// 修改月份(数值)
LocalDate newMonth = date.with(ChronoField.MONTH_OF_YEAR, 12);
System.out.println("修改月份: " + newMonth); // 2025-12-15
// 修改日期
LocalDate newDay = date.with(ChronoField.DAY_OF_MONTH, 1);
System.out.println("修改日期: " + newDay); // 2025-08-01
}
}
💡 常用
ChronoField
常量:
YEAR
:年份MONTH_OF_YEAR
:月份(1-12)DAY_OF_MONTH
:月中的天(1-31)DAY_OF_YEAR
:年中的天(1-365/366)ERA
:纪元(如 AD/BC)
方向二:使用调整器(with(TemporalAdjuster)
)
1. 使用内置调整器(TemporalAdjusters
)
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
public class WithAdjusterExample {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2025, 8, 15); // 2025-08-15
System.out.println("原始日期: " + date);
// 本月第一天
LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth());
System.out.println("本月第一天: " + firstDay); // 2025-08-01
// 本月最后一天
LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("本月最后一天: " + lastDay); // 2025-08-31
// 下一个周日
LocalDate nextSunday = date.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println("下一个周日: " + nextSunday); // 2025-08-17
// 本月第一个周三
LocalDate firstWednesday = date.with(TemporalAdjusters.firstInMonth(DayOfWeek.WEDNESDAY));
System.out.println("本月第一个周三: " + firstWednesday); // 2025-08-06
// 下一个工作日(自定义逻辑需自己实现)
}
}
2. 自定义调整器
import java.time.LocalDate;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;
// 自定义:下一个工作日(跳过周六周日)
public class NextWorkingDay implements TemporalAdjuster {
@Override
public Temporal adjustInto(Temporal temporal) {
LocalDate date = LocalDate.from(temporal);
do {
date = date.plusDays(1);
} while (date.getDayOfWeek() == DayOfWeek.SATURDAY ||
date.getDayOfWeek() == DayOfWeek.SUNDAY);
return date;
}
}
// 使用自定义调整器
LocalDate nextWorkDay = date.with(new NextWorkingDay());
System.out.println("下一个工作日: " + nextWorkDay);
使用技巧
技巧 1:链式调用
LocalDate result = date
.withYear(2030)
.withMonth(1)
.withDayOfMonth(1);
// 结果: 2030-01-01
技巧 2:结合 plus()
/minus()
使用
// 设置为下个月的第一天
LocalDate nextMonthFirst = date.plusMonths(1).withDayOfMonth(1);
技巧 3:使用 YearMonth
辅助
import java.time.YearMonth;
// 设置为某年某月的最后一天
YearMonth ym = YearMonth.of(2025, 2);
LocalDate febEnd = ym.atEndOfMonth(); // 2025-02-28
常见错误
错误 | 说明 | 修复 |
---|---|---|
DateTimeException |
设置无效日期,如 2025-02-30 |
确保日期合法(会自动处理闰年) |
UnsupportedTemporalTypeException |
使用不支持的 TemporalField |
使用 ChronoField 中定义的字段 |
NullPointerException |
调整器为 null |
确保 TemporalAdjuster 不为 null |
误解不可变性 | 以为 with() 修改了原对象 |
记住:必须接收返回值 |
// 错误示例
LocalDate date = LocalDate.now();
date.withYear(2030); // 忘记接收返回值!
System.out.println(date); // 仍然是当前日期!
注意事项
- ⚠️ 不可变性:
with()
不改变原对象,必须接收返回值。 - ⚠️ 自动校正:如果设置的日期无效,会自动调整(异常模式):
LocalDate.of(2025, 1, 32).withDayOfMonth(32); // 抛异常 // 但 LocalDate.of(2025, 1, 31).plusDays(1) 会变成 2025-02-01
实际上,
withDayOfMonth(32)
在 1月 会抛DateTimeException
,因为 1月没有32日。 - ⚠️ 闰年处理:设置
2月29日
时,非闰年会抛异常。 - ⚠️ 调整器可重用:
TemporalAdjusters
的静态方法返回的调整器是线程安全的,可共享。
最佳实践与性能优化
✅ 最佳实践
实践 | 说明 |
---|---|
✅ 优先使用 withYear() , withMonth() 等便捷方法 |
比 with(ChronoField.XXX) 更直观 |
✅ 复杂逻辑使用 TemporalAdjusters |
如“本月最后一个周五” |
✅ 封装常用调整逻辑 | 提高代码复用性 |
✅ 链式调用提升可读性 | 适合连续修改多个字段 |
⚙️ 性能优化
with()
方法性能极高,为 O(1) 操作。- 内置调整器(如
firstDayOfMonth
)经过优化,无需担心性能。 - 自定义调整器避免复杂循环或 I/O 操作。
- 在循环中可缓存常用的
TemporalAdjuster
实例。
总结
方法类型 | 示例 | 适用场景 |
---|---|---|
with(field, value) |
date.with(ChronoField.YEAR, 2030) |
直接设置具体字段值 |
with(adjuster) |
date.with(firstDayOfMonth()) |
实现复杂日期逻辑 |
便捷方法 | date.withYear(2030) |
简单字段修改,代码更清晰 |
✅ 一句话总结:
LocalDate.with()
是修改日期的“标准方式”,通过不可变模式保证线程安全,结合字段设置和调整器机制,既能简单赋值,又能实现复杂日期运算。