控制台交互是 Java 初學者接觸的第一種 I/O 方式。本文系統講解 Scanner 輸入與 System.out 輸出的核心 API、常用模式、異常處理與最佳實踐。
System.out 是 PrintStream 類型,主要方法:
| 方法 | 說明 | 示例 |
|---|---|---|
print() | 不換行輸出 | System.out.print("Hello"); |
println() | 輸出並換行 | System.out.println("World"); |
printf() | 格式化輸出 (C 風格) | System.out.printf("%.2f%%", 99.5); |
format() | 同 printf,返回 PrintStream | System.out.format("%s: %d", "Age", 18); |
%s 字符串%d 整數 (十進制)%f 浮點數 (默認 6 位小數)%.2f 保留 2 位小數%n 平台無關換行符%t 日期時間 (如 %tF 年-月-日,%tT 時:分:秒)java.util.Scanner 可解析基本類型與字符串,默認分隔符為空白字符 (空格、制表符、換行符)。
Scanner sc = new Scanner(System.in); // 標準輸入
Scanner sc = new Scanner(new File("data.txt")); // 文件輸入
Scanner sc = new Scanner("1 2 3"); // 字符串輸入
| 方法 | 讀取內容 | 異常 | 備註 |
|---|---|---|---|
next() | 下一個 Token (非空白字符序列) | NoSuchElementException | 不包含分隔符 |
nextLine() | 整行內容 (含空格,至換行符) | NoSuchElementException | **會消耗換行符** |
nextInt() | 下一個 int | InputMismatchException | 不消耗換行符 |
nextDouble() | 下一個 double | InputMismatchException | |
nextBoolean() | 下一個 boolean (true/false 不區分大小寫) | InputMismatchException | |
hasNext() | 是否有下一個 Token | - | 非阻塞檢查 |
hasNextInt() | 下一個是否為 int | - | 安全讀取前檢查 |
Scanner sc = new Scanner(System.in);
int age = sc.nextInt(); // 輸入 "18\n",讀取 18,**殘留 "\n"**
String name = sc.nextLine(); // 直接讀到殘留的 "\n",返回空字符串!
// 解決:nextInt() 後額外調用一次 nextLine() 消耗換行符
sc.nextLine(); // 消耗換行符
String name = sc.nextLine(); // 正常讀取下一行
import java.util.Scanner;
public class ConsoleIO {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== 學生信息錄入 ===");
// 1. 讀取姓名 (可能含空格)
System.out.print("姓名: ");
String name = sc.nextLine();
// 2. 讀取年齡 (整數)
System.out.print("年齡: ");
while (!sc.hasNextInt()) {
System.out.print("請輸入整數: ");
sc.next(); // 丟棄無效輸入
}
int age = sc.nextInt();
sc.nextLine(); // 消耗換行符!
// 3. 讀取身高 (浮點數)
System.out.print("身高(m): ");
while (!sc.hasNextDouble()) {
System.out.print("請輸入數字: ");
sc.next();
}
double height = sc.nextDouble();
sc.nextLine(); // 消耗換行符
// 4. 讀取愛好 (多行,以 "END" 結束)
System.out.println("愛好 (輸入 END 結束): ");
StringBuilder hobbies = new StringBuilder();
while (sc.hasNextLine()) {
String line = sc.nextLine();
if ("END".equalsIgnoreCase(line)) break;
hobbies.append(line).append("; ");
}
// 5. 格式化輸出
System.out.printf("%n=== 信息確認 ===%n");
System.out.printf("姓名: %s%n", name);
System.out.printf("年齡: %d 歲%n", age);
System.out.printf("身高: %.2f m%n", height);
System.out.printf("愛好: %s%n", hobbies);
sc.close(); // 關閉釋放資源
}
}
Scanner sc = new Scanner("1,2,3,4,5");
sc.useDelimiter(","); // 或正則 "\\s*,\\s*"
while (sc.hasNextInt()) System.out.println(sc.nextInt());
Scanner sc = new Scanner("User: Alice, Age: 20");
sc.findInLine("User: (\\w+)"); // 移動到匹配位置
String name = sc.match().group(1); // "Alice"
// 命令行
java ConsoleIO < input.txt > output.txt
// 代碼中無需修改,System.in 自動關聯文件
try (Scanner sc = new Scanner(System.in)) { ... } 自動關閉sc.next() 清除錯誤 Token,否則死循環sc.close() 會調用 System.in.close(),導致後續無法再讀取標準輸入,**全程僅創建一個 Scanner**控制台 I/O 核心口訣:輸出用 printf 格式化,輸入用 Scanner 次系列,nextInt 後必消耗換行,hasNext 預檢防異常,全程單例 Scanner,try-with-resources 保平安。掌握這些模式,足以應對所有控制台交互場景。