综合项目
本课是Java教程的最终项目,综合运用所有知识点。
项目概述
实现一个命令行待办清单(Todo List)应用,支持:
- 添加待办事项
- 查看待办列表
- 标记完成
- 删除待办
- 数据持久化(保存到文件)
- 按状态/优先级筛选
数据模型
JAVA
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Todo implements Serializable {
private static final long serialVersionUID = 1L;
public enum Priority { LOW, MEDIUM, HIGH }
public enum Status { PENDING, COMPLETED }
private int id;
private String title;
private String description;
private Priority priority;
private Status status;
private LocalDateTime createdAt;
private LocalDateTime completedAt;
public Todo(int id, String title, String description, Priority priority) {
this.id = id;
this.title = title;
this.description = description;
this.priority = priority;
this.status = Status.PENDING;
this.createdAt = LocalDateTime.now();
}
// getter/setter
public int getId() { return id; }
public String getTitle() { return title; }
public String getDescription() { return description; }
public Priority getPriority() { return priority; }
public Status getStatus() { return status; }
public LocalDateTime getCreatedAt() { return createdAt; }
public LocalDateTime getCompletedAt() { return completedAt; }
public void setStatus(Status status) {
this.status = status;
if (status == Status.COMPLETED) {
this.completedAt = LocalDateTime.now();
}
}
public boolean isCompleted() {
return status == Status.COMPLETED;
}
@Override
public String toString() {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
String statusIcon = isCompleted() ? "✅" : "⬜";
String priorityIcon;
switch (priority) {
case HIGH: priorityIcon = "🔴"; break;
case MEDIUM: priorityIcon = "🟡"; break;
default: priorityIcon = "🟢"; break;
}
return String.format("%s %s [%d] %s (%s)",
statusIcon, priorityIcon, id, title, createdAt.format(formatter));
}
}
管理类
JAVA
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
public class TodoManager {
private List<Todo> todos;
private int nextId;
private static final String FILE_NAME = "todos.dat";
public TodoManager() {
this.todos = new ArrayList<>();
this.nextId = 1;
loadFromFile();
}
// 添加待办
public Todo addTodo(String title, String description, Todo.Priority priority) {
Todo todo = new Todo(nextId++, title, description, priority);
todos.add(todo);
saveToFile();
return todo;
}
// 完成待办
public boolean completeTodo(int id) {
Todo todo = findById(id);
if (todo != null && !todo.isCompleted()) {
todo.setStatus(Todo.Status.COMPLETED);
saveToFile();
return true;
}
return false;
}
// 删除待办
public boolean deleteTodo(int id) {
Todo todo = findById(id);
if (todo != null) {
todos.remove(todo);
saveToFile();
return true;
}
return false;
}
// 查找待办
public Todo findById(int id) {
return todos.stream()
.filter(t -> t.getId() == id)
.findFirst()
.orElse(null);
}
// 获取所有待办
public List<Todo> getAllTodos() {
return new ArrayList<>(todos);
}
// 获取待处理的待办
public List<Todo> getPendingTodos() {
return todos.stream()
.filter(t -> !t.isCompleted())
.collect(Collectors.toList());
}
// 获取已完成的待办
public List<Todo> getCompletedTodos() {
return todos.stream()
.filter(Todo::isCompleted)
.collect(Collectors.toList());
}
// 按优先级排序
public List<Todo> sortByPriority() {
return todos.stream()
.sorted((a, b) -> {
int cmp = b.getPriority().compareTo(a.getPriority());
return cmp != 0 ? cmp : a.getId() - b.getId();
})
.collect(Collectors.toList());
}
// 按创建时间排序
public List<Todo> sortByDate() {
return todos.stream()
.sorted(Comparator.comparing(Todo::getCreatedAt))
.collect(Collectors.toList());
}
// 统计
public int getTotal() { return todos.size(); }
public int getPendingCount() { return (int) todos.stream().filter(t -> !t.isCompleted()).count(); }
public int getCompletedCount() { return (int) todos.stream().filter(Todo::isCompleted).count(); }
// 保存到文件
private void saveToFile() {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_NAME))) {
oos.writeObject(todos);
oos.writeInt(nextId);
} catch (IOException e) {
System.out.println("保存失败:" + e.getMessage());
}
}
// 从文件加载
@SuppressWarnings("unchecked")
private void loadFromFile() {
File file = new File(FILE_NAME);
if (!file.exists()) return;
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_NAME))) {
todos = (List<Todo>) ois.readObject();
nextId = ois.readInt();
} catch (IOException | ClassNotFoundException e) {
System.out.println("加载失败:" + e.getMessage());
}
}
}
主程序
JAVA
import java.util.List;
import java.util.Scanner;
public class TodoApp {
private static TodoManager manager = new TodoManager();
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("=== 待办清单 ===");
int choice;
do {
showMenu();
choice = getIntInput("请选择:");
switch (choice) {
case 1: addTodo(); break;
case 2: listTodos(); break;
case 3: completeTodo(); break;
case 4: deleteTodo(); break;
case 5: showStatistics(); break;
case 6: listByPriority(); break;
case 0: System.out.println("再见!"); break;
default: System.out.println("无效选择");
}
} while (choice != 0);
scanner.close();
}
private static void showMenu() {
System.out.println("\n--- 菜单 ---");
System.out.println("1. 添加待办");
System.out.println("2. 查看所有待办");
System.out.println("3. 标记完成");
System.out.println("4. 删除待办");
System.out.println("5. 统计信息");
System.out.println("6. 按优先级排序");
System.out.println("0. 退出");
}
private static void addTodo() {
System.out.print("标题:");
String title = scanner.nextLine().trim();
if (title.isEmpty()) {
System.out.println("标题不能为空");
return;
}
System.out.print("描述:");
String desc = scanner.nextLine().trim();
System.out.println("优先级:1-低 2-中 3-高");
int p = getIntInput("选择:");
Todo.Priority priority;
switch (p) {
case 1: priority = Todo.Priority.LOW; break;
case 3: priority = Todo.Priority.HIGH; break;
default: priority = Todo.Priority.MEDIUM;
}
Todo todo = manager.addTodo(title, desc, priority);
System.out.println("添加成功:" + todo);
}
private static void listTodos() {
List<Todo> todos = manager.getAllTodos();
if (todos.isEmpty()) {
System.out.println("暂无待办事项");
return;
}
System.out.println("\n--- 待办列表 ---");
for (Todo todo : todos) {
System.out.println(todo);
}
System.out.printf("共 %d 项(待处理 %d,已完成 %d)%n",
manager.getTotal(), manager.getPendingCount(), manager.getCompletedCount());
}
private static void completeTodo() {
listTodos();
int id = getIntInput("输入要完成的ID:");
if (manager.completeTodo(id)) {
System.out.println("已标记完成");
} else {
System.out.println("ID无效或已完成");
}
}
private static void deleteTodo() {
listTodos();
int id = getIntInput("输入要删除的ID:");
if (manager.deleteTodo(id)) {
System.out.println("已删除");
} else {
System.out.println("ID无效");
}
}
private static void showStatistics() {
System.out.println("\n=== 统计信息 ===");
System.out.println("总计:" + manager.getTotal());
System.out.println("待处理:" + manager.getPendingCount());
System.out.println("已完成:" + manager.getCompletedCount());
double rate = manager.getTotal() > 0 ?
(double) manager.getCompletedCount() / manager.getTotal() * 100 : 0;
System.out.printf("完成率:%.1f%%%n", rate);
}
private static void listByPriority() {
List<Todo> todos = manager.sortByPriority();
System.out.println("\n--- 按优先级排序 ---");
for (Todo todo : todos) {
System.out.println(todo);
}
}
private static int getIntInput(String prompt) {
System.out.print(prompt);
while (!scanner.hasNextInt()) {
System.out.print("请输入数字:");
scanner.next();
}
int value = scanner.nextInt();
scanner.nextLine(); // 消耗换行符
return value;
}
}
运行示例
TEXT
=== 待办清单 ===
--- 菜单 ---
1. 添加待办
2. 查看所有待办
3. 标记完成
4. 删除待办
5. 统计信息
6. 按优先级排序
0. 退出
请选择:1
标题:学习Java
描述:完成Java教程第32课
优先级:1-低 2-中 3-高
选择:3
添加成功:⬜ 🔴 [1] 学习Java (2026-06-24 14:30)
请选择:2
--- 待办列表 ---
⬜ 🔴 [1] 学习Java (2026-06-24 14:30)
共 1 项(待处理 1,已完成 0)
知识点总结
| 知识点 | 应用 |
|---|---|
| 类与对象 | Todo、TodoManager类设计 |
| 封装 | 属性私有,getter/setter |
| 枚举 | Priority、Status枚举 |
| 集合 | List存储待办,Stream操作 |
| 异常处理 | 文件IO异常处理 |
| 文件IO | 序列化保存/加载数据 |
| 日期时间 | LocalDateTime记录时间 |
| Lambda | Stream排序、过滤 |
| 泛型 | List |
扩展功能
1. 按日期筛选
JAVA
public List<Todo> getTodayTodos() {
LocalDate today = LocalDate.now();
return todos.stream()
.filter(t -> t.getCreatedAt().toLocalDate().equals(today))
.collect(Collectors.toList());
}
2. 搜索功能
JAVA
public List<Todo> search(String keyword) {
String lower = keyword.toLowerCase();
return todos.stream()
.filter(t -> t.getTitle().toLowerCase().contains(lower) ||
t.getDescription().toLowerCase().contains(lower))
.collect(Collectors.toList());
}
3. 导出为文本
JAVA
public void exportToText(String filename) throws IOException {
try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
writer.println("=== 待办清单导出 ===");
writer.println("导出时间:" + LocalDateTime.now());
writer.println();
for (Todo todo : todos) {
writer.println(todo);
if (!todo.getDescription().isEmpty()) {
writer.println(" " + todo.getDescription());
}
writer.println();
}
}
}
❓ 常见问题
Q 如何扩展为GUI应用?
A 可以用JavaFX或Swing实现图形界面。
Q 如何支持多用户?
A 每个用户一个数据文件,或使用数据库存储。
Q 如何添加提醒功能?
A 使用定时器(Timer/ScheduledExecutorService)检查到期任务。
📖 小节
- 综合运用类、集合、异常、IO、Lambda等知识
- 数据持久化使用序列化
- Stream API简化集合操作
- 枚举定义固定常量
📝 作业
- 扩展功能: 添加搜索和按日期筛选功能
- 数据导出: 支持导出为CSV格式
- GUI版本: 用JavaFX实现图形界面版本
🎉 恭喜完成Java教程!
通过32节课的学习,你已经掌握了:
- Java基础语法
- 面向对象编程
- 集合框架
- 异常处理
- 文件IO
- 正则表达式和JSON处理
接下来可以继续学习:
- Spring Boot框架
- 数据库编程(JDBC/MyBatis)
- Web开发
- 设计模式



