自定义 temporalquery 的核心是实现函数式接口 queryfrom,从 temporalaccessor 中安全读取字段并返回指定类型结果,需用 issupported 判断支持性、用 chronofield 枚举、保持无副作用。

自定义 TemporalQuery 的核心是实现它的函数式接口,让它能从任意 TemporalAccessor(如 LocalDateTime、ZonedDateTime 等)中提取你关心的特定字段或计算结果。
理解 TemporalQuery 的作用
TemporalQuery<r></r> 是一个函数式接口,只定义了一个方法:R queryFrom(TemporalAccessor temporal)
它不修改时间对象,只读取并返回你需要的信息——比如星期几、是否闰年、毫秒数、自定义格式字符串等。
写一个最简自定义查询:提取星期几中文名
例如,想把任意时间转成“周一”“周二”这样的中文表示:
TemporalQuery<string> CHINESE_DAY_OF_WEEK = temporal -> {
int value = temporal.get(ChronoField.DAY_OF_WEEK);
return switch (value) {
case 1 -> "周一";
case 2 -> "周二";
case 3 -> "周三";
case 4 -> "周四";
case 5 -> "周五";
case 6 -> "周六";
case 7 -> "周日";
default -> "未知";
};
};</string>
用法:String day = LocalDateTime.now().query(CHINESE_DAY_OF_WEEK); // 返回"周三"
抽取复合信息:获取“年-月-日 时:分”字符串
如果不想用 DateTimeFormatter,也可以用 TemporalQuery 直接拼接:
- 先检查是否支持
YEAR、MONTH_OF_YEAR、DAY_OF_MONTH、HOUR_OF_DAY、MINUTE_OF_HOUR字段 - 用
temporal.isSupported(field)做安全判断,避免抛异常 - 组合成字符串,缺失字段可设默认值(如无时分则填 "00:00")
示例:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
TemporalQuery<string> YYYY_MM_DD_HH_MM = temporal -> {
int y = temporal.get(ChronoField.YEAR);
int m = temporal.get(ChronoField.MONTH_OF_YEAR);
int d = temporal.get(ChronoField.DAY_OF_MONTH);
int h = temporal.isSupported(ChronoField.HOUR_OF_DAY)
? temporal.get(ChronoField.HOUR_OF_DAY) : 0;
int min = temporal.isSupported(ChronoField.MINUTE_OF_HOUR)
? temporal.get(ChronoField.MINUTE_OF_HOUR) : 0;
return String.format("%d-%02d-%02d %02d:%02d", y, m, d, h, min);
};</string>
封装成可复用的工具类方法
推荐把常用查询逻辑封装为静态方法,提升可读性和复用性:
public class TemporalQueries {
public static final TemporalQuery<boolean> IS_LEAP_YEAR = temporal -> {
if (temporal instanceof Year year) {
return year.isLeap();
}
if (temporal.isSupported(ChronoField.YEAR)) {
int year = temporal.get(ChronoField.YEAR);
return Year.isLeap(year);
}
throw new UnsupportedTemporalTypeException("无法判断闰年:缺少 YEAR 字段");
};
public static TemporalQuery<long> epochSeconds() {
return temporal -> {
if (temporal instanceof Instant instant) {
return instant.getEpochSecond();
}
if (temporal instanceof ChronoZonedDateTime> zdt) {
return zdt.toInstant().getEpochSecond();
}
if (temporal instanceof LocalDateTime ldt) {
// 需指定时区才能转为 Instant
throw new IllegalArgumentException("LocalDateTime 无法直接转 epoch seconds,缺少时区信息");
}
throw new UnsupportedTemporalTypeException("不支持的时间类型");
};
}
}</long></boolean>
调用:
boolean leap = Year.now().query(TemporalQueries.IS_LEAP_YEAR);<br> Long sec = Instant.now().query(TemporalQueries.epochSeconds());
注意边界情况和类型安全
自定义 TemporalQuery 时容易忽略几点:
-
不是所有 TemporalAccessor 都支持全部字段:比如
LocalDate没有HOUR_OF_DAY,直接 get 会抛异常,务必先用isSupported()判断 -
避免硬编码字段值:优先用
ChronoField枚举,而不是 magic number -
返回类型要明确:泛型
R决定了 query 方法的返回值类型,别返回 null(除非 R 是引用类型且允许) - 不要在 query 中修改入参:TemporalQuery 必须是纯函数,保持无副作用
不复杂但容易忽略细节。只要抓住“只读 + 类型适配 + 安全取值”三个要点,就能写出健壮的自定义查询。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










