ArrayList 更适合绝大多数待办工具,因增删集中在末尾,其随机访问快、内存连续、遍历性能稳;LinkedList 仅适合频繁中间操作,否则额外开销大、GC 压力高、迭代更慢。

用 ArrayList 存任务比 LinkedList 更合适
绝大多数待办工具的增删集中在末尾(新增任务、完成并移除),ArrayList 的随机访问快、内存连续,遍历时性能更稳。除非你频繁在列表中间插入或删除(比如按优先级实时重排),否则别默认选 LinkedList——它每个节点额外占 8–16 字节,GC 压力更大,且迭代器实际更慢。
实操建议:
- 声明类型用接口:
List,后续换实现成本低tasks = new ArrayList(); - 初始化时预估容量:
new ArrayList(20),避免多次扩容(每次扩容约 1.5 倍,触发数组复制) - 删除已完成任务,别用
for (int i = 0; i 正向遍历 +remove(i),会跳过下一个元素;改用Iterator.remove()或倒序索引
任务对象必须重写 equals() 和 hashCode()
否则用 tasks.contains(task) 或放进 HashSet 去重时永远返回 false,哪怕两个任务标题、时间完全一样。Java 默认的 equals() 只比较引用地址。
关键点:
立即学习“Java免费学习笔记(深入)”;
- 只对业务上“算同一个任务”的字段参与比较,比如
id(推荐 UUID 或自增 long)或title + dueDate组合 -
hashCode()必须和equals()逻辑一致,否则HashMap查找失效 - 用 IDE 自动生成(如 IntelliJ 的
Alt+Insert → equals() and hashCode()),别手写漏字段
保存到文件时优先选 ObjectOutputStream 还是 JSON?
直接序列化成二进制(ObjectOutputStream)最省事,但不兼容、不可读、无法跨语言、升级类结构后容易反序列化失败。JSON 是更稳妥的选择,尤其当你以后可能加 Web 端或移动端。
实操路径:
- 用
Gson或Jackson库,避免手写字符串拼接 - 任务类加
@SerializedName("due_time")控制字段名,别让 Java 驼峰名直接变成 JSON 里的dueTime - 写入前确保目录存在:
Files.createDirectories(Paths.get("data")),否则FileNotFoundException - 用
try-with-resources包裹FileWriter,防止文件句柄泄漏
try (FileWriter writer = new FileWriter("data/tasks.json")) {
gson.toJson(tasks, writer);
}
搜索功能别直接用 String.contains() 全遍历
用户搜“报销”,结果把“不报销”“已报销完成”都捞出来,体验差。简单改进就能提升准确度:
- 搜标题时加边界:用
title.toLowerCase().startsWith(query.toLowerCase())做前缀匹配,响应更快 - 支持多字段查(标题 + 描述):先用
stream().filter(),但数据量超 200 条后明显卡顿,这时该考虑用TreeSet按标题排序后二分,或引入Lucene简易索引 - 中文搜索注意全角/半角空格、标点,预处理时统一转半角、去首尾空格










