首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 控制台輸入三代演進:BufferedReader → Scanner → Console 全解析

     編輯:Java 程式設計入門

前言:從輸入流到現代化 API 的演進

控制台輸入是 Java 初學者接觸的第一個 I/O 場景。隨著 JDK 版本演進,API 經歷了三代:**字元流橋接 → 正則掃描器 → 專用控制台物件**。本文系統梳理三代用法、優缺點與適用場景。

第一代:JDK 1.0~1.4 —— BufferedReader 橋接輸入流

import java.io.*;

public class ConsoleInputV1 {
    public static void main(String[] args) throws IOException {
        // System.in (InputStream) → InputStreamReader (橋接) → BufferedReader (緩衝)
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("請輸入姓名: ");
        String name = br.readLine(); // 僅支援讀取整行字串

        System.out.print("請輸入年齡: ");
        String ageStr = br.readLine();
        int age = Integer.parseInt(ageStr); // 手動轉型,拋 NumberFormatException

        System.out.printf("姓名: %s, 年齡: %d%n", name, age);
    }
}

特點

  • **唯一選擇**(JDK 1.4 前)。
  • **僅回傳 String**,基本型別需手動 parseXxx。
  • 需處理 IOException(受檢異常)。
  • 無提示功能,readLine() 不支援密碼隱藏。

第二代:JDK 5.0 —— Scanner 正則掃描器

import java.util.Scanner;

public class ConsoleInputV2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.print("請輸入姓名: ");
        String name = sc.nextLine(); // 讀整行

        System.out.print("請輸入年齡: ");
        int age = sc.nextInt(); // 直接讀 int,自動轉型

        System.out.print("請輸入身高: ");
        double height = sc.nextDouble(); // 直接讀 double

        System.out.print("請輸入是否學生: ");
        boolean isStudent = sc.nextBoolean(); // true/false

        System.out.printf("姓名: %s, 年齡: %d, 身高: %.1f, 學生: %b%n",
                name, age, height, isStudent);

        sc.close(); // 關閉掃描器(也會關閉 System.in,後續不可再用)
    }
}

核心優勢

方法功能
next()下一個 token(空白分隔)
nextLine()整行(含空白)
nextInt/Long/Short/Byte直接讀基本型別整數
nextDouble/Float直接讀浮點數
nextBoolean()讀 true/false
nextBigInteger/BigDecimal大數字型別
hasNextXxx()預檢下一 token 型別
useDelimiter(pattern)自定義分隔符(正則)

注意事項

  • nextInt() 後緩衝區殘留換行符,後續 nextLine() 會讀到空行 → **混用時在 nextInt() 後呼叫一次 nextLine() 清空換行**。
  • sc.close() 會關閉 System.in,**全程只能建立一個 Scanner**,否則後續讀取失效。
  • 非執行緒安全,多執行緒需同步或各自建立。

第三代:JDK 6.0 —— Console 專用控制台物件

import java.io.Console;

public class ConsoleInputV3 {
    public static void main(String[] args) {
        Console console = System.console();
        if (console == null) {
            System.err.println("無法取得 Console 物件(可能在 IDE 運行、重導向、非終端機環境)");
            return;
        }

        // 1. 讀取字串(可帶提示)
        String name = console.readLine("請輸入姓名: ");

        // 2. 讀取密碼(不回顯,回傳 char[] 避免字串常駐記憶體)
        char[] pwd = console.readPassword("請輸入密碼: ");
        String password = new String(pwd); // 用完立即清除
        java.util.Arrays.fill(pwd, ' '); // 安全清除

        // 3. 格式化輸出
        console.printf("歡迎 %s,密碼長度 %d%n", name, password.length());

        // 4. 取得 Reader/Writer 進行進階操作
        // console.reader() / console.writer()
    }
}

獨特優勢

  • 密碼隱藏輸入:readPassword() 回傳 char[],非 String,可主動清除,減少記憶體殘留風險。
  • 內建提示:readLine("prompt: ") 一體化。
  • 編碼自動適配:根據終端機編碼處理中文等非 ASCII 字元。
  • 格式化輸出:printf() 直接支援。

重大限制

  • IDE 運行時 System.console() 回傳 null(Eclipse、IntelliJ、VS Code 內建終端多為管道而非真實 TTY)。
  • **僅適用真實終端機**(cmd、bash、PowerShell、Terminal.app)。
  • 無直接讀基本型別方法,仍需自行解析。

三代對比總結表

維度BufferedReaderScannerConsole
JDK 版本1.0+5.0+6.0+
核心能力唯讀行字串正則掃描 + 直接讀基本型別真實終端機專用、密碼隱藏
適用環境任何有 System.in 的環境任何有 System.in 的環境**僅真實 TTY/終端機**
IDE 相容性✅ 完美✅ 完美❌ 回傳 null
密碼隱藏❌❌✅ readPassword()
基本型別直接讀❌ 手動 parse✅❌
編碼處理手動指定平台預設自動適配終端
執行緒安全❌❌❌

最佳實踐建議

  1. 教學/測試/IDE 環境:**首選 Scanner**,API 豐富、支援基本型別、IDE 完美相容。
  2. 需密碼隱藏的生產 CLI 工具:**首選 Console**,但需檢測 null 並降級到 Scanner(提示明文輸入)。
  3. 高效能/大量資料輸入:BufferedReader + 手動解析,最低開銷。
  4. 混用 nextXxx() 與 nextLine():**次呼叫 nextLine() 清空換行符**。
  5. Scanner 關閉策略:全程單例,try-with-resources 管理,或不關閉(JVM 結束自動回收)。
  6. 安全清除密碼:Arrays.fill(charArray, ' '),勿依賴 GC。

綜合範例:自動適配 Console/Scanner

import java.io.Console;
import java.util.Scanner;

public class SmartConsoleInput {
    public static void main(String[] args) {
        Console console = System.console();
        Scanner scanner = new Scanner(System.in);

        // 讀取姓名
        String name = (console != null) 
                ? console.readLine("姓名: ") 
                : readLine(scanner, "姓名: ");

        // 讀取密碼
        String password;
        if (console != null) {
            char[] pwd = console.readPassword("密碼: ");
            password = new String(pwd);
            java.util.Arrays.fill(pwd, ' ');
        } else {
            System.out.print("密碼(明文): ");
            password = scanner.nextLine();
        }

        System.out.printf("登入: %s / %s%n", name, "*".repeat(password.length()));
        scanner.close();
    }

    static String readLine(Scanner sc, String prompt) {
        System.out.print(prompt);
        return sc.nextLine();
    }
}

總結

  • 三代 API 各有定位:**BufferedReader 基石、Scanner 通用主力、Console 安全專用**。
  • **IDE 開發階段 Scanner 無敵**;**部署到真實終端的 CLI 工具 Console 獨步**。
  • 理解 System.console() == null 的成因與對策,是 CLI 開發者的必修課。
  • 安全場景**務必用 char[] 接收密碼,用畢立即清除**。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved