昨天學習了 Java 的 Inheritance(繼承),開始了解父類別、子類別、extends 和 super。
今天先回到我們的記帳系統,解決一個實際使用時很容易遇到的問題:
如果使用者輸入錯誤,程式會怎麼辦?
例如程式要求輸入消費金額:
請輸入消費金額:
正常應該輸入:
150
但如果不小心輸入:
abc
因為 abc 不是整數,程式就可能直接發生錯誤並停止。
所以今天要學習 Exception Handling(例外處理)。
什麼是 Exception?
Exception 可以理解成:
程式執行過程中發生的「例外狀況」。
例如:
int amount = scanner.nextInt();
這行程式預期使用者輸入整數。
如果輸入:
100
沒有問題。
但如果輸入:
一百
或:
abc
Java 就無法把它當成 int 處理,因此會產生 Exception。
如果沒有處理這個問題,程式就可能直接停止。
try 和 catch
Java 可以使用:
try {
} catch (Exception e) {
}
來處理可能發生的錯誤。
可以先簡單理解成:
try
↓
嘗試執行程式
發生錯誤
↓
catch
↓
處理錯誤
例如:
try {
System.out.print("請輸入金額:");
int amount = scanner.nextInt();
System.out.println("金額:" + amount);
} catch (Exception e) {
System.out.println("輸入錯誤!");
}
如果輸入:
100
結果:
金額:100
如果輸入:
abc
程式不會直接結束,而是顯示:
輸入錯誤!
這就是 Exception Handling 最基本的用途。
今天遇到的 InputMismatchException
其實我們可以寫得更精確一點。
當 nextInt() 收到不是整數的內容時,常見的例外是:
InputMismatchException
所以先加入:
import java.util.InputMismatchException;
接著可以寫:
try {
int amount = scanner.nextInt();
} catch (InputMismatchException e) {
System.out.println("請輸入正確的數字!");
}
這樣就專門處理「輸入格式不是整數」的問題。
為什麼 catch 後還要 nextLine()?
假設使用者輸入:
abc
發生錯誤之後,這個錯誤的輸入還留在 Scanner 裡。
所以通常需要:
scanner.nextLine();
把這次錯誤輸入清掉。
例如:
catch (InputMismatchException e) {
System.out.println("請輸入正確的數字!");
scanner.nextLine();
}
不然下一次讀取資料時可能又遇到問題。
今天的小實作:保護記帳系統
今天把例外處理加入我們的記帳系統。
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:
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. 離開");
}
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();
scanner.nextLine();
System.out.print("請輸入消費分類:");
String category = scanner.nextLine();
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("目前沒有消費紀錄。");
} else {
for (int i = 0; i < expenses.size(); i++) {
Expense expense = expenses.get(i);
System.out.println(
(i + 1) + ". "
+ expense.getItem()
+ "|" + expense.getAmount() + " 元"
+ "|" + expense.getCategory()
);
}
}
}
}
正常輸入的情況
執行程式:
===== 個人記帳系統 =====
輸入:
===== 新增消費 =====
請輸入消費項目:午餐
請輸入消費金額:120
請輸入消費分類:飲食
記帳成功!
這時候資料就會正常加入。
如果金額輸入錯誤
例如:
請輸入消費項目:午餐
請輸入消費金額:abc
以前程式可能直接出現錯誤並停止。
現在則會顯示:
金額輸入錯誤,請輸入數字!
接著程式還可以繼續回到主選單:
===== 個人記帳系統 =====
這就是今天最重要的改進。
主選單輸入錯誤也能處理
我們也替主選單加上:
try {
int choice = scanner.nextInt();
} catch (InputMismatchException e) {
System.out.println("輸入錯誤,請輸入數字!");
}
所以如果使用者原本應該輸入:
1
2
3
結果輸入:
hello
程式也不會直接當掉。
而是顯示:
輸入錯誤,請輸入數字!
然後再次顯示選單。
try、catch 怎麼記?
今天最重要的其實只有兩個關鍵字。
try
try {
// 可能發生錯誤的程式
}
可以理解成:
「先試著執行看看。」
catch
catch (InputMismatchException e) {
// 發生錯誤時要做什麼
}
可以理解成:
「如果真的發生這個錯誤,就在這裡處理。」
所以我把它記成:
try
│
├── 沒有錯誤 → 正常執行
│
└── 發生 Exception
↓
catch
↓
處理錯誤
Exception Handling 有什麼用?
今天做完之後,我發現 Exception Handling 不只是考試會出現的 Java 語法。
它其實對實際程式非常重要。
因為我們不能保證使用者每一次都按照要求輸入資料。
例如要求輸入:
消費金額:100
使用者可能輸入:
100元
也可能輸入:
abc
甚至可能按錯鍵。
如果一個輸入錯誤就讓整個程式停止,使用體驗會很差。
所以程式除了「功能可以正常執行」之外,也要考慮:
如果使用者做錯了,程式能不能繼續運作?
這也是今天最大的收穫。
Day 15 學習心得
今天學習了 Java 的 Exception Handling 例外處理,主要認識 try、catch 和 InputMismatchException。
之前寫程式時,我比較在意正常輸入之後能不能得到正確結果,沒有特別想到使用者可能輸入錯誤。實際把錯誤輸入放進記帳系統測試之後,才發現如果沒有例外處理,一個很小的輸入錯誤就可能讓整個程式停止。
加入 try 和 catch 之後,即使使用者輸入錯誤,程式也可以顯示提示並繼續執行。我覺得今天的內容讓記帳系統不只是「可以跑」,而是開始考慮實際使用時可能發生的問題。
目前進行到第 15 天,也正式完成 30 天挑戰的一半。前半段從 Java 基礎語法一路學到 ArrayList、Method 和物件導向,現在也開始加入例外處理,接下來希望可以把這些觀念真正整合成更完整的記帳功能。