Todo List TUI in Java
This one is practical on day one. Build a todo manager you can use while studying.
This version is complete and runnable in one Java file.
Quick Run (from repo root)
1cd Site/static/code/examples/java
2javac TodoCli.java
3java TodoCliFeatures
- add tasks
- list tasks
- mark tasks done
- remove tasks
- save to disk automatically
Code (Single Public Class)
1import java.io.IOException;
2import java.nio.file.Files;
3import java.nio.file.Path;
4import java.util.ArrayList;
5import java.util.List;
6import java.util.Locale;
7import java.util.Scanner;
8
9public class TodoCli {
10 public static void main(String[] args) {
11 Path saveFile = Path.of("todo-java.txt");
12 Store store = new Store(saveFile);
13 store.load();
14
15 Scanner scanner = new Scanner(System.in);
16 System.out.println("Commands: add, list, done, remove, quit");
17
18 while (true) {
19 System.out.print("> ");
20 String command = scanner.nextLine().trim().toLowerCase(Locale.ROOT);
21
22 switch (command) {
23 case "add":
24 System.out.print("Task: ");
25 String text = scanner.nextLine().trim();
26 if (!text.isEmpty()) {
27 store.add(text);
28 store.save();
29 }
30 break;
31 case "list":
32 store.print();
33 break;
34 case "done":
35 System.out.print("Task id: ");
36 int doneId = parseId(scanner.nextLine());
37 if (store.markDone(doneId)) {
38 store.save();
39 }
40 break;
41 case "remove":
42 System.out.print("Task id: ");
43 int removeId = parseId(scanner.nextLine());
44 if (store.remove(removeId)) {
45 store.save();
46 }
47 break;
48 case "quit":
49 System.out.println("Saved to " + saveFile);
50 return;
51 default:
52 System.out.println("Use: add, list, done, remove, quit");
53 }
54 }
55 }
56
57 private static int parseId(String raw) {
58 try {
59 return Integer.parseInt(raw.trim());
60 } catch (NumberFormatException e) {
61 return -1;
62 }
63 }
64
65 private static class Store {
66 private final Path saveFile;
67 private final List<Task> tasks = new ArrayList<>();
68 private int nextId = 1;
69
70 private Store(Path saveFile) {
71 this.saveFile = saveFile;
72 }
73
74 private void add(String text) {
75 tasks.add(new Task(nextId++, text, false));
76 System.out.println("Added.");
77 }
78
79 private boolean markDone(int id) {
80 for (Task task : tasks) {
81 if (task.id == id) {
82 task.done = true;
83 System.out.println("Marked done.");
84 return true;
85 }
86 }
87 System.out.println("Task not found.");
88 return false;
89 }
90
91 private boolean remove(int id) {
92 boolean removed = tasks.removeIf(task -> task.id == id);
93 System.out.println(removed ? "Removed." : "Task not found.");
94 return removed;
95 }
96
97 private void print() {
98 if (tasks.isEmpty()) {
99 System.out.println("No tasks yet.");
100 return;
101 }
102 for (Task task : tasks) {
103 String box = task.done ? "[x]" : "[ ]";
104 System.out.println(task.id + ". " + box + " " + task.text);
105 }
106 }
107
108 private void load() {
109 if (!Files.exists(saveFile)) {
110 return;
111 }
112 try {
113 for (String line : Files.readAllLines(saveFile)) {
114 String[] parts = line.split("\\|", 3);
115 if (parts.length < 3) {
116 continue;
117 }
118 int id = Integer.parseInt(parts[0]);
119 boolean done = Boolean.parseBoolean(parts[1]);
120 String text = parts[2];
121 tasks.add(new Task(id, text, done));
122 nextId = Math.max(nextId, id + 1);
123 }
124 } catch (IOException | NumberFormatException e) {
125 System.out.println("Starting with empty list.");
126 tasks.clear();
127 nextId = 1;
128 }
129 }
130
131 private void save() {
132 List<String> lines = new ArrayList<>();
133 for (Task task : tasks) {
134 lines.add(task.id + "|" + task.done + "|" + task.text);
135 }
136 try {
137 Files.write(saveFile, lines);
138 } catch (IOException e) {
139 System.out.println("Could not save tasks.");
140 }
141 }
142 }
143
144 private static class Task {
145 private final int id;
146 private final String text;
147 private boolean done;
148
149 private Task(int id, String text, boolean done) {
150 this.id = id;
151 this.text = text;
152 this.done = done;
153 }
154 }
155}Run It
1javac TodoCli.java
2java TodoCliWhy It Matters
You get real CRUD plus persistence, but still in a small codebase you can read in one sitting.