Java初学者项目实战:实现一个简单的提醒事项工具

选用JavaFX而非Swing因后者样式陈旧且UI线程交互易抛IllegalStateException;JavaFX提供Timeline、Alert及绑定控件,更适配提醒闭环,需用Platform.runLater更新UI、ScheduledExecutorService管理定时任务、ObservableList实现自动刷新。

为什么不用 Swing 而选 JavaFX 来做提醒工具界面

Swing 组件默认样式陈旧,Timer 和线程调度与 UI 交互容易出 IllegalStateException: Not on FX application thread 错误;JavaFX 提供原生的 TimelineAlert 和绑定式控件(如 ObservableList),更适合实现「添加事项→设置时间→到点弹窗提醒」这个闭环。初学者若硬套 Swing,大概率会在 SwingUtilities.invokeLaterTimer 嵌套里迷失。

实操建议:

  • javafx.application.Application 启动,别写 main 里直接 new Frame
  • 所有 UI 更新(比如在列表加一条新事项)必须走 Platform.runLater()
  • 提醒触发逻辑不要放在 Button.setOnAction 里直接 sleep —— 那会卡死整个界面

如何让提醒准时触发且不重复弹窗

核心是用 ScheduledExecutorService 管理定时任务,而不是轮询或 Thread.sleep。每个提醒事项对应一个 ScheduledFuture,保存在 Map> 中,方便取消或替换。

常见错误现象:同一事项点了两次“添加”,结果到点弹两个一模一样的 Alert

实操建议:

  • 给每条事项生成唯一 ID(例如 UUID.randomUUID().toString()),作为 map 的 key
  • 添加前先检查该 ID 是否已存在,存在则调用 future.cancel(true) 再新建
  • 触发时用 Alert alert = new Alert(AlertType.INFORMATION),设 alert.setHeaderText(null) 避免默认标题干扰
  • 务必调用 alert.showAndWait() 而非 show(),否则用户还没点确认,后续提醒可能叠加

数据怎么存?别急着上 SQLite 或 JSON 文件

初学者项目目标是跑通流程,不是造轮子。内存存储 + 序列化到本地文件(如 reminders.ser)足够用,且避免引入 JDBC 或 Jackson 依赖带来的配置和异常处理负担。

使用场景:关闭程序再打开,上次添加的事项还在列表里。

实操建议:

  • 定义类时加上 implements Serializable,字段用 private static final long serialVersionUID = 1L
  • 读写用 ObjectOutputStream / ObjectInputStream,路径固定为 "./reminders.ser"
  • 捕获 IOExceptionClassNotFoundException,失败时清空列表并 log,别让程序崩溃
  • 不要在 JavaFX 主线程里做文件 IO —— 用 Executors.newCachedThreadPool() 异步读写

为什么点击“删除”后列表没刷新

因为直接操作了 ArrayList,但 JavaFX 的 ListView 绑定的是 ObservableList。改底层数据源却不通知 UI,等于白删。

典型错误代码:

items.remove(selectedItem); // items 是 ArrayList

实操建议:

  • 初始化时用 FXCollections.observableArrayList() 创建列表
  • 绑定到 ListView:
    listView.setItems(observableItems);
  • 删除时调用 observableItems.remove(selectedItem),自动触发 UI 更新
  • 如果要支持多选删除,用 listView.getSelectionModel().getSelectedItems() 获取 ObservableList 视图,再批量 remove
JavaFX 的绑定机制和线程模型是初学者最容易卡住的地方。功能可以简单,但数据流(添加 → 存储 → 定时 → 弹窗 → 删除 → 刷新)每个环节的线程归属和更新方式必须对得上,否则就是“看着代码全对,运行起来哪都不对”。