iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
自我挑戰組

Java 程式設計與實作:30 天打造個人記帳系統系列 第 19 篇

記帳系統實作:新增「修改消費紀錄」功能

  • 分享至 

  • xImage
  •  

昨天完成了「刪除消費紀錄」功能,現在如果輸入錯誤的帳目,已經可以直接把它刪除。

不過實際使用時,有時候可能只是金額輸入錯誤,例如:

午餐|120 元|飲食

後來才發現真正的金額是:

午餐|150 元|飲食

如果只是金額錯誤,直接把整筆資料刪掉再重新新增有點麻煩。

所以 Day 19 要加入新的功能:修改消費紀錄。

今天要完成的功能

昨天的主選單是:

===== 個人記帳系統 =====

  1. 新增消費
  2. 查看紀錄
  3. 查看總支出
  4. 分類支出統計
  5. 刪除消費紀錄
  6. 離開

今天修改成:

===== 個人記帳系統 =====

  1. 新增消費
  2. 查看紀錄
  3. 查看總支出
  4. 分類支出統計
  5. 刪除消費紀錄
  6. 修改消費紀錄
  7. 離開

假設目前有:

  1. 早餐|60 元|飲食
  2. 午餐|120 元|飲食
  3. 捷運|30 元|交通

選擇修改功能:

請輸入要修改的紀錄編號:2

接著重新輸入:

新的消費項目:午餐
新的消費金額:150
新的消費分類:飲食

最後就會變成:

  1. 午餐|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();

分類則繼續使用選單:

  1. 飲食
  2. 交通
  3. 購物
  4. 娛樂

最後利用 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 學習內容的進一步應用。

實際執行看看

目前有:

===== 消費紀錄 =====

  1. 早餐|60 元|飲食
  2. 午餐|120 元|飲食
  3. 捷運|30 元|交通

選擇:

請選擇功能:6

程式顯示:

===== 修改消費紀錄 =====
===== 消費紀錄 =====

  1. 早餐|60 元|飲食
  2. 午餐|120 元|飲食
  3. 捷運|30 元|交通
    請輸入要修改的紀錄編號:2

接著:

目前資料:午餐|120 元|飲食
請輸入新的消費項目:午餐
請輸入新的消費金額:150
請選擇消費分類:

  1. 飲食
  2. 交通
  3. 購物
  4. 娛樂
    請輸入選項:1
    修改成功!

再次查看:

===== 消費紀錄 =====

  1. 早餐|60 元|飲食
  2. 午餐|150 元|飲食
  3. 捷運|30 元|交通

成功修改。

修改後統計也會跟著改變

這裡有一個我覺得很有意思的地方。

原本:

早餐: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,讓新增和修改功能可以共用。現在開始不只是一直增加功能,也會注意程式是不是有重複的地方,以及能不能整理得更乾淨。

目前記帳系統已經可以做到新增、查看、修改、刪除和統計資料,基本的資料管理功能也越來越完整。


上一篇
記帳系統實作:新增「刪除消費紀錄」功能
下一篇
記帳系統實作:加入「消費預算」與超支提醒
系列文
Java 程式設計與實作:30 天打造個人記帳系統 共 23 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言