优先选用 PriorityQueue,因其支持 O(log n) 入队和 O(1) 查堆顶,契合日程“快速取最近待办”需求;ArrayList 需手动排序,TreeSet 不允许多值且删非首项低效;需显式传入比较器,否则易抛 ClassCastException。

为什么用 PriorityQueue 而不是 ArrayList 或 TreeSet
因为日程安排核心是「按时间顺序快速取最近待办」,PriorityQueue 提供 O(log n) 入队 + O(1) 查看堆顶(最近事件),比手动排序 ArrayList 高效;而 TreeSet 虽然有序,但不允许多个相同时间的任务(除非自定义比较器处理相等情况),且删除非首项成本高。实际场景中,你常要反复添加新日程、立刻看到“下一个要做的事”,PriorityQueue 天然匹配这个读多写多、只关心顶端的模式。
PriorityQueue 的比较器必须显式传入,否则会报 ClassCastException
Java 默认 PriorityQueue 不接受 null,也不支持对自定义类自动排序。如果你直接存 Event 对象而不指定比较逻辑,运行时抛出 ClassCastException 是大概率事件——尤其当 Event 没实现 Comparable 时。
实操建议:
- 用 lambda 写比较器最轻量:
new PriorityQueue((a, b) -> Integer.compare(a.time, b.time)) - 如果时间相同还想按标题排序,链式比较:
(a, b) -> { int c = Integer.compare(a.time, b.time); return c != 0 ? c : a.title.compareTo(b.title); } - 别依赖
compareTo方法自动触发——没重写就炸
控制台交互里,Scanner 读字符串后紧接着读整数容易卡住
典型现象:输入 add meeting 10 后,程序停住不动,下一行 nextLine() 或 nextInt() 读不到东西。本质是 nextInt() 不吞掉换行符,下次 nextLine() 立刻读到空行。
立即学习“Java免费学习笔记(深入)”;
安全做法:
- 统一用
nextLine()读整行,再用split()解析命令和参数 - 如果非用
nextInt(),后面紧跟一个scanner.nextLine()清缓冲区 - 别在同一个
Scanner实例里混用next*和nextLine(),除非你清楚每一步的缓冲区状态
任务时间用 int 表示小时数够用,但得约定好格式
简单日程程序没必要上 LocalDateTime,用 int time(比如 9 表示上午 9 点,14 表示下午 2 点)既省事又避免时区/解析问题。但必须明确约束:
- 时间范围限定在
0–23,输入越界要提示,不能静默失败 - 显示时补零更友好:
String.format("%02d:00", event.time) - 如果后续想支持“上午/下午”或分钟,现在就预留字段(如加
int minute),别硬塞进time做运算
真正麻烦的从来不是堆怎么建,而是用户输错时间、输错命令、输一半就回车——这些边界情况比排序逻辑更早暴露问题。










