昨天完成了「刪除消費紀錄」功能,現在如果輸入錯誤的帳目,已經可以直接把它刪除。
不過實際使用時,有時候可能只是金額輸入錯誤,例如:
午餐|120 元|飲食
後來才發現真正的金額是:
午餐|150 元|飲食
如果只是金額錯誤,直接把整筆資料刪掉再重新新增有點麻煩。
所以 Day 19 要加入新的功能:修改消費紀錄。
今天要完成的功能
昨天的主選單是:
===== 個人記帳系統 =====
今天修改成:
===== 個人記帳系統 =====
假設目前有:
選擇修改功能:
請輸入要修改的紀錄編號:2
接著重新輸入:
新的消費項目:午餐
新的消費金額:150
新的消費分類:飲食
最後就會變成:
今天會重新用到 Setter
Day 13 學習 Encapsulation 時,曾經建立過 Setter:
public void setItem(String item) {
this.item = item;
}
public void setAmount(int amount) {
this.amount = amount;
}
public void setCategory(String category) {
this.category = category;
}
當時主要是在學習封裝,所以沒有真正大量使用。
今天終於可以把它們拿來修改記帳資料。
例如:
expense.setItem("晚餐");
expense.setAmount(200);
expense.setCategory("飲食");
就可以修改原本 Expense Object 裡面的資料。
第一步:把 Setter 加回 Expense
目前的 Expense:
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 void setItem(String item) {
this.item = item;
}
public void setAmount(int amount) {
if (amount >= 0) {
this.amount = amount;
}
}
public void setCategory(String category) {
this.category = category;
}
這樣 Expense 就同時具有:
Getter → 取得資料
Setter → 修改資料
第二步:建立 editExpense()
建立新的 Method:
public static void editExpense()
先檢查目前有沒有紀錄:
if (expenses.size() == 0) {
System.out.println("目前沒有可以修改的紀錄。");
return;
}
如果沒有資料,就不需要繼續執行。
第三步:選擇要修改哪一筆
先顯示所有紀錄:
showExpenses();
接著:
System.out.print("請輸入要修改的紀錄編號:");
int number = scanner.nextInt();
scanner.nextLine();
和昨天刪除功能一樣,需要把使用者看到的編號轉換成 ArrayList Index:
int index = number - 1;
例如:
使用者輸入:2
↓
2 - 1
↓
Index = 1
接著取得這個 Object:
Expense expense = expenses.get(index);
第四步:輸入新的資料
接著重新輸入:
System.out.print("請輸入新的消費項目:");
String newItem = scanner.nextLine();
System.out.print("請輸入新的消費金額:");
int newAmount = scanner.nextInt();
scanner.nextLine();
分類則繼續使用選單:
最後利用 Setter:
expense.setItem(newItem);
expense.setAmount(newAmount);
expense.setCategory(newCategory);
就可以直接修改原本的 Object。
Day 19 完整程式
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 void setItem(String item) {
this.item = item;
}
public void setAmount(int amount) {
if (amount >= 0) {
this.amount = amount;
}
}
public void setCategory(String category) {
this.category = 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:
editExpense();
break;
case 7:
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. 修改消費紀錄");
System.out.println("7. 離開");
}
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();
String category = chooseCategory();
Expense expense =
new Expense(item, amount, category);
expenses.add(expense);
System.out.println("記帳成功!");
} catch (InputMismatchException e) {
System.out.println("輸入錯誤,請輸入數字!");
scanner.nextLine();
}
}
public static String chooseCategory() {
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();
switch (categoryChoice) {
case 1:
return "飲食";
case 2:
return "交通";
case 3:
return "購物";
case 4:
return "娛樂";
default:
return "其他";
}
}
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();
}
}
public static void editExpense() {
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 expense = expenses.get(index);
System.out.println(
"目前資料:"
+ expense.getItem()
+ "|" + expense.getAmount() + " 元"
+ "|" + expense.getCategory()
);
System.out.print("請輸入新的消費項目:");
String newItem = scanner.nextLine();
System.out.print("請輸入新的消費金額:");
int newAmount = scanner.nextInt();
String newCategory = chooseCategory();
expense.setItem(newItem);
expense.setAmount(newAmount);
expense.setCategory(newCategory);
System.out.println("修改成功!");
} else {
System.out.println("沒有這筆紀錄!");
}
} catch (InputMismatchException e) {
System.out.println("輸入錯誤,請輸入正確的數字!");
scanner.nextLine();
}
}
}
今天順便整理了一個重複的程式
前幾天選擇分類時,每次都需要寫:
System.out.println("1. 飲食");
System.out.println("2. 交通");
System.out.println("3. 購物");
System.out.println("4. 娛樂");
現在新增和修改都需要選分類,如果兩邊都重新寫一次,程式會出現很多重複內容。
所以今天另外建立:
public static String chooseCategory()
它會讓使用者選擇分類,最後使用 return 回傳分類名稱。
例如使用者輸入:
2
Method:
case 2:
return "交通";
最後:
String category = chooseCategory();
category 就會得到:
交通
這也是前面 Method 學習內容的進一步應用。
實際執行看看
目前有:
===== 消費紀錄 =====
選擇:
請選擇功能:6
程式顯示:
===== 修改消費紀錄 =====
===== 消費紀錄 =====
接著:
目前資料:午餐|120 元|飲食
請輸入新的消費項目:午餐
請輸入新的消費金額:150
請選擇消費分類:
再次查看:
===== 消費紀錄 =====
成功修改。
修改後統計也會跟著改變
這裡有一個我覺得很有意思的地方。
原本:
早餐:60
午餐:120
捷運:30
總支出:210 元
修改午餐之後:
早餐:60
午餐:150
捷運:30
再次執行:
查看總支出
結果就會自動變成:
總支出:240 元
因為統計功能每次都會重新讀取 expenses 裡目前最新的資料。
所以不需要自己另外修改總金額。
Getter 和 Setter 終於一起使用了
Day 13 學習封裝時:
getItem()
getAmount()
getCategory()
負責讀取資料。
今天:
setItem()
setAmount()
setCategory()
負責修改資料。
現在就可以更清楚地理解:
Expense
│
┌───────┴───────┐
↓ ↓
Getter Setter
↓ ↓
取得資料 修改資料
這也讓前面學過的 Encapsulation 真正用進目前的專案裡。
Day 19 學習心得
今天完成了修改消費紀錄的功能,現在如果輸入錯誤,不需要把整筆資料刪除再重新新增,而是可以直接選擇紀錄並修改項目、金額和分類。
這次也真正使用到之前學過的 Setter。當時學 Getter 和 Setter 時覺得只是物件導向的一種寫法,今天實際拿來修改 Expense Object 後,才比較清楚它們真正的用途。
另外,我也把重複的分類選擇程式整理成 chooseCategory() Method,讓新增和修改功能可以共用。現在開始不只是一直增加功能,也會注意程式是不是有重複的地方,以及能不能整理得更乾淨。
目前記帳系統已經可以做到新增、查看、修改、刪除和統計資料,基本的資料管理功能也越來越完整。