昨天完成了「分類支出統計」,現在除了可以知道總共花多少錢,也可以看到飲食、交通、購物和娛樂分別花了多少。
目前系統已經可以新增和分析資料,不過我發現還少了一個很實際的功能:
如果不小心記錯一筆帳,要怎麼刪掉?
所以 Day 18 要加入 刪除消費紀錄,並正式使用之前學過的:
ArrayList.remove()
今天想完成的功能
目前的選單是:
===== 個人記帳系統 =====
今天改成:
===== 個人記帳系統 =====
假設目前有:
如果選擇:
請輸入要刪除的紀錄編號:2
希望程式可以顯示:
已刪除:捷運
之後再次查看紀錄:
ArrayList 的 remove()
之前 Day 9 學習 ArrayList 時有簡單提到:
remove()
它可以把 ArrayList 裡面的資料刪除。
例如:
ArrayList items = new ArrayList<>();
items.add("早餐");
items.add("捷運");
items.add("午餐");
現在資料的位置是:
Index 0 → 早餐
Index 1 → 捷運
Index 2 → 午餐
如果執行:
items.remove(1);
就會刪除:
捷運
剩下:
早餐
午餐
使用者看到的編號和 Index 不一樣
這裡有一個需要注意的地方。
我們顯示給使用者的是:
但是 ArrayList 真正的 Index 是:
早餐 → 0
捷運 → 1
午餐 → 2
所以如果使用者輸入:
2
代表要刪除「捷運」。
但是程式真正要使用:
expenses.remove(1);
因此需要:
int index = number - 1;
例如:
使用者輸入 2
↓
2 - 1
↓
Index = 1
↓
刪除捷運
這和之前學 Array 時「Index 從 0 開始」是同樣的概念。
建立 deleteExpense() Method
因為我們已經習慣把不同功能分成 Method,所以今天建立:
public static void deleteExpense()
基本版本:
public static void deleteExpense() {
System.out.print("請輸入要刪除的紀錄編號:");
int number = scanner.nextInt();
scanner.nextLine();
int index = number - 1;
expenses.remove(index);
System.out.println("刪除成功!");
}
不過這裡還有一個問題。
如果目前只有 3 筆資料,使用者卻輸入:
10
就會發生錯誤。
所以還需要檢查編號。
檢查輸入的紀錄編號
可以使用:
if (number >= 1 && number <= expenses.size())
意思是:
number >= 1
而且:
number <= 紀錄數量
才是有效的編號。
完整判斷:
if (number >= 1 && number <= expenses.size()) {
int index = number - 1;
expenses.remove(index);
System.out.println("刪除成功!");
} else {
System.out.println("沒有這筆紀錄!");
}
刪除前先取得資料
如果直接:
expenses.remove(index);
資料刪掉之後,我們就不方便顯示剛剛刪除了什麼。
所以可以先:
Expense deletedExpense = expenses.get(index);
再刪除:
expenses.remove(index);
最後:
System.out.println(
"已刪除:" + deletedExpense.getItem()
);
這樣使用者會知道自己剛剛刪掉哪一筆。
Day 18 完整程式
今天把刪除功能整合進目前的記帳系統:
import java.util.Scanner;
import java.util.ArrayList;
import java.util.InputMismatchException;
class Expense {
private String item;
private int amount;
private String category;
Expense(String item, int amount, String category) {
this.item = item;
this.amount = amount;
this.category = category;
}
public String getItem() {
return item;
}
public int getAmount() {
return amount;
}
public String getCategory() {
return category;
}
}
public class Main {
static Scanner scanner = new Scanner(System.in);
static ArrayList expenses = new ArrayList<>();
public static void main(String[] args) {
boolean running = true;
while (running) {
showMenu();
try {
System.out.print("請選擇功能:");
int choice = scanner.nextInt();
scanner.nextLine();
switch (choice) {
case 1:
addExpense();
break;
case 2:
showExpenses();
break;
case 3:
calculateTotal();
break;
case 4:
categoryStatistics();
break;
case 5:
deleteExpense();
break;
case 6:
running = false;
System.out.println("已離開個人記帳系統!");
break;
default:
System.out.println("沒有這個選項!");
}
} catch (InputMismatchException e) {
System.out.println("輸入錯誤,請輸入數字!");
scanner.nextLine();
}
}
scanner.close();
}
public static void showMenu() {
System.out.println();
System.out.println("===== 個人記帳系統 =====");
System.out.println("1. 新增消費");
System.out.println("2. 查看紀錄");
System.out.println("3. 查看總支出");
System.out.println("4. 分類支出統計");
System.out.println("5. 刪除消費紀錄");
System.out.println("6. 離開");
}
public static void addExpense() {
System.out.println();
System.out.println("===== 新增消費 =====");
System.out.print("請輸入消費項目:");
String item = scanner.nextLine();
try {
System.out.print("請輸入消費金額:");
int amount = scanner.nextInt();
System.out.println();
System.out.println("請選擇消費分類:");
System.out.println("1. 飲食");
System.out.println("2. 交通");
System.out.println("3. 購物");
System.out.println("4. 娛樂");
System.out.print("請輸入選項:");
int categoryChoice = scanner.nextInt();
scanner.nextLine();
String category;
switch (categoryChoice) {
case 1:
category = "飲食";
break;
case 2:
category = "交通";
break;
case 3:
category = "購物";
break;
case 4:
category = "娛樂";
break;
default:
category = "其他";
}
Expense expense =
new Expense(item, amount, category);
expenses.add(expense);
System.out.println("記帳成功!");
} catch (InputMismatchException e) {
System.out.println("輸入錯誤,請輸入數字!");
scanner.nextLine();
}
}
public static void showExpenses() {
System.out.println();
System.out.println("===== 消費紀錄 =====");
if (expenses.size() == 0) {
System.out.println("目前沒有消費紀錄。");
return;
}
for (int i = 0; i < expenses.size(); i++) {
Expense expense = expenses.get(i);
System.out.println(
(i + 1) + ". "
+ expense.getItem()
+ "|" + expense.getAmount() + " 元"
+ "|" + expense.getCategory()
);
}
}
public static void calculateTotal() {
System.out.println();
System.out.println("===== 支出統計 =====");
if (expenses.size() == 0) {
System.out.println("目前沒有消費紀錄。");
return;
}
int total = 0;
for (int i = 0; i < expenses.size(); i++) {
total += expenses.get(i).getAmount();
}
System.out.println(
"目前共有 " + expenses.size() + " 筆消費"
);
System.out.println("總支出:" + total + " 元");
}
public static void categoryStatistics() {
System.out.println();
System.out.println("===== 分類支出統計 =====");
if (expenses.size() == 0) {
System.out.println("目前沒有消費紀錄。");
return;
}
int foodTotal = 0;
int transportTotal = 0;
int shoppingTotal = 0;
int entertainmentTotal = 0;
for (int i = 0; i < expenses.size(); i++) {
Expense expense = expenses.get(i);
switch (expense.getCategory()) {
case "飲食":
foodTotal += expense.getAmount();
break;
case "交通":
transportTotal += expense.getAmount();
break;
case "購物":
shoppingTotal += expense.getAmount();
break;
case "娛樂":
entertainmentTotal += expense.getAmount();
break;
}
}
System.out.println("飲食:" + foodTotal + " 元");
System.out.println("交通:" + transportTotal + " 元");
System.out.println("購物:" + shoppingTotal + " 元");
System.out.println("娛樂:" + entertainmentTotal + " 元");
}
public static void deleteExpense() {
System.out.println();
System.out.println("===== 刪除消費紀錄 =====");
if (expenses.size() == 0) {
System.out.println("目前沒有可以刪除的紀錄。");
return;
}
showExpenses();
try {
System.out.print("請輸入要刪除的紀錄編號:");
int number = scanner.nextInt();
scanner.nextLine();
if (number >= 1 && number <= expenses.size()) {
int index = number - 1;
Expense deletedExpense =
expenses.get(index);
expenses.remove(index);
System.out.println(
"已刪除:" + deletedExpense.getItem()
);
} else {
System.out.println("沒有這筆紀錄!");
}
} catch (InputMismatchException e) {
System.out.println("輸入錯誤,請輸入紀錄編號!");
scanner.nextLine();
}
}
}
實際執行看看
假設目前有三筆紀錄:
===== 消費紀錄 =====
主選單輸入:
請選擇功能:5
程式會顯示:
===== 刪除消費紀錄 =====
===== 消費紀錄 =====
結果:
已刪除:捷運
再次查看:
===== 消費紀錄 =====
成功把第二筆刪除了。
刪除之後編號為什麼會改變?
原本:
Index 0 → 早餐
Index 1 → 捷運
Index 2 → 電影
刪掉 Index 1 的捷運之後,ArrayList 會自動整理:
Index 0 → 早餐
Index 1 → 電影
所以我們不需要自己移動資料。
這也是 ArrayList 比一般 Array 方便的地方之一。
如果輸入不存在的編號
例如目前只有:
卻輸入:
請輸入要刪除的紀錄編號:10
因為有:
if (number >= 1 && number <= expenses.size())
所以程式不會執行 remove(),而是顯示:
沒有這筆紀錄!
這也避免程式因為錯誤的 Index 而發生 Exception。
今天用到的 &&
今天還出現:
&&
它代表 AND(而且)。
例如:
number >= 1 && number <= expenses.size()
意思就是:
編號必須大於等於 1,而且不能超過目前的紀錄數量。
兩個條件都成立,才可以刪除。
例如目前有 3 筆:
1 → 可以
2 → 可以
3 → 可以
4 → 不可以
0 → 不可以
-1 → 不可以
Day 18 學習心得
今天替記帳系統加入了刪除消費紀錄的功能,也正式使用之前學過的 ArrayList.remove()。
實作時我發現最需要注意的是使用者看到的紀錄從 1 開始,但是 ArrayList 的 Index 從 0 開始,所以刪除之前需要先把使用者輸入的編號減 1。
另外也加入了編號範圍判斷和 Exception Handling,避免使用者輸入不存在的紀錄或錯誤格式時讓程式停止。
現在記帳系統已經不只是可以新增資料,也開始可以管理資料。看到自己從前面單純的 Java 語法練習,一步一步做到可以新增、查看、統計和刪除資料的程式,開始比較有完成一個小型系統的感覺。