2013年10月23日 星期三

Scanner(System.in) 無法取的輸入的問題

    當你的只使用一個 Scanner(System.in) 在你的程式中並沒有甚麼問題,但是如果你有兩個類別都使用 Scanner(System.in) 來取得輸入時,最後使用 Scanner(System.in) 來取得輸入的類別是無法取得輸入,除非第一個使用的那個類別沒有呼叫close來關閉 Scanner。

    範例程式如下:
// InputDemo.java
import java.io.IOException;
import java.util.Scanner;

public class InputDemo {
    public static void main(String[] args) throws IOException {
        OtherInput otherInput = new OtherInput();

        int number = -1;
        Scanner scanner = new Scanner(System.in);
        
        // 嘗試執行下列敘述會得到IO例外訊息
        //System.out.println("System.in.available()" + System.in.available());
        
        System.out.print("Input a number:");
        if (scanner.hasNextInt()) {
            number = scanner.nextInt();
        }
        scanner.close();
        // 因為 scanner.nextInt() 沒有執行,所以 number 為 -1
        System.out.println("You input a number " + number);
    }
}

// OtherInput.java 
import java.util.Scanner;
public class OtherInput {
    public OtherInput() {
        Scanner scanner = new Scanner(System.in);
        
        int age = 0;
        String name = null;
        
        System.out.print("Please input your name:");
        if (scanner.hasNextLine()) {
            name = scanner.nextLine();
        }
        
        System.out.print("Please input your age:");
        if (scanner.hasNextInt()) {
            age = scanner.nextInt();
        }
        scanner.close();
        System.out.println("Your name: " + name + " and age: " + age);
    }
}

    在 Eclipse 下如果你沒有關閉 Scanner 會有一個警告訊息:"Resource leak: 'scanner' is never closed"。所以不建議不關閉 Scanner 物件。為什麼關閉 Scanner 物件會有問題呢? 因為當你執行 scanner.close() 時也會把 System.in 標準輸入也關閉掉,所以最後使用Scanner 物件的 calss 無法正常的取得輸入。
   你可以試著把上面的範例 InputDemo.java 中的 System.in.available() 註解符號拿掉,你會得到下列的例外訊息:
   Exception in thread "main" java.io.IOException: Stream closed
 at java.io.BufferedInputStream.getInIfOpen(Unknown Source)
 at java.io.BufferedInputStream.available(Unknown Source)
 at InputDemo.main(InputDemo.java:10)

   所以當你有多個類別要使用 Scanner(System.in) 取得輸入時,最好可以在主類別建立一個 Scanner 物件,然後將該物件傳遞給需要的類別,然後在主類別呼叫 Scanner 的 close 方法。

[其他參考]
java.util.NoSuchElementException - Scanner reading user input

沒有留言: