使用 try、catch


來看一個簡單的程式,使用者可以連續輸入整數,最後輸入0結束後會顯示輸入數的平均值:

package cc.openhome;

import java.util.Scanner;

public class Average {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        double sum = 0;
        int count = 0;
        int number;
        while(true) {
            number = scanner.nextInt();
            if(number == 0) {
                break;
            }
            sum += number;
            count++;
        }
        System.out.printf("平均 %.2f%n", sum / count);
    }
}

如果使用者正確地輸入每個整數,程式會如預期地顯示平均:

10 20 30 40 0
平均 25.00

如果使用者不小心輸入錯誤,那就會出現奇怪的訊息,例如第三個數輸入為3o,而不是30了:

10 20 3o 40 0
Exception in thread "main" java.util.InputMismatchException
    at java.util.Scanner.throwFor(Scanner.java:909)
    at java.util.Scanner.next(Scanner.java:1530)
    at java.util.Scanner.nextInt(Scanner.java:2160)
    at java.util.Scanner.nextInt(Scanner.java:2119)
    at cc.openhome.Average.main(Average.java:11)
Java Result: 1

這段錯誤訊息對除錯是很有價值的,不過先看到錯誤訊息的第一行:

Exception in thread "main" java.util.InputMismatchException

Scanner物件的nextInt()方法,可以將使用者輸入的下一個字串剖析為int值,如果出現InputMismatchException錯誤訊息,表示不符合Scanner物件預期,因為Scanner物件預期下一個字串本身要代表數字。

Java中所有錯誤都會被包裹為物件,如果你願意,可以嘗試(try)捕捉(catch)代表錯誤的物件後作一些處理。例如:

package cc.openhome;

import java.util.*;

public class Average2 {
    public static void main(String[] args) {
        try {
            Scanner scanner = new Scanner(System.in);
            double sum = 0;
            int count = 0;
            int number;
            while (true) {
                number = scanner.nextInt();
                if (number == 0) {
                    break;
                }
                sum += number;
                count++;
            }
            System.out.printf("平均 %.2f%n", sum / count);
        } catch (InputMismatchException ex) {
            System.out.println("必須輸入整數");
        }
    }
}

這邊使用了trycatch語法,JVM會嘗試執行try區塊中的程式碼,如果發生錯誤,執行流程會跳離錯誤發生點,然後比對catch括號中宣告的型態,是否符合被拋出的錯誤物件型態,如果是的話,就執行catch區塊中的程式碼。

一個執行無誤的範例如下所示:

10 20 30 40 0
平均 25.00

範例中如果nextInt()發生InputMismatchException,流程就會跳到型態宣告為InputMismatchExceptioncatch區塊,執行完catch區塊後,之後沒有其它程式碼了,所以程式就結束了。一個執行時輸入有誤的範例如下所示:

10 20 3o 40 0
必須輸入整數

這個範例示範了如何運用trycatch,在錯誤發生時顯示更友善錯誤訊息。有時錯誤可以在捕捉處理之後,嘗試回復程式正常執行流程。例如:

package cc.openhome;

import java.util.*;

public class Average3 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        double sum = 0;
        int count = 0;
        int number;
        while (true) {
            try {
                number = scanner.nextInt();
                if (number == 0) {
                    break;
                }
                sum += number;
                count++;
            } catch (InputMismatchException ex) {
                System.out.printf("略過非整數輸入:%s%n", scanner.next());
            }
        }
        System.out.printf("平均 %.2f%n", sum / count);
    }
}

如果nextInt()發生了InputMismatchException錯誤,執行流程就會跳到catch區塊,執行完catch區塊之後,由於還在while迴圈中,所以還可繼續下一個迴圈流程。

一個輸入錯誤時的結果示範如下,對於正確的整數輸入予以加總,對於錯誤的輸入則顯示略過,最後顯示平均值:

10 20 3o 40 0
略過非整數輸入:3o
平均 23.33

不過就Java在例外處理的設計上,並不鼓勵捕捉InputMismatchException並重新恢復執行流程,原因在介紹例外繼承架構時會進行說明。