3.10 Scanner类的bug
在有了一些使用 Scanner 的经验后,有必要提醒你一下,它存在一个出人意料的行为。下面的代码片段让用户输入姓名和年龄:
System.out.print("What is your name? ");name = in.nextLine();System.out.print("What is your age? ");age = in.nextInt();System.out.printf("Hello %s, age %d\n", name, age);
其输出可能类似于以下这样:
Hello Grace Hopper, age 45
先读取 String 再读取 int 时,一切都正常,但如果先读取 int 再读取 String,将发生怪异的事情。
System.out.print("What is your age? ");age = in.nextInt();System.out.print("What is your name? ");name = in.nextLine();System.out.printf("Hello %s, age %d\n", name, age);
如果尝试运行上述示例代码,你将发现它根本不允许输入姓名,而在你输入年龄后会直接显示输出:
What is your name? Hello , age 45
要想明白其中的原因,你必须知道的是,Scanner 并不像我们那样将输入视为多行;相反,它获得的是一个如图 3-3 所示的“字符流”。

图 3-3:Scanner 眼中的字符流
其中的箭头指向 Scanner 将读取的下一个字符。调用 nextInt 时,它会不断读取字符,直到遇到非数字字符。图 3-4 显示了调用 nextInt 后流的状态。

图 3-4:调用 nextInt 后的字符流
此时,nextInt 返回 45。接下来,程序显示提示 What is your name?,并调用 nextLine;这个方法会不断读取字符,直到遇到换行符。然而,由于下一个字符就是换行符,因此 nextLine 返回一个空字符串("")。
为解决这个问题,需要在 nextInt 后面多调用一次 nextLine。
System.out.print("What is your age? ");age = in.nextInt();in.nextLine(); // 读取换行符System.out.print("What is your name? ");name = in.nextLine();System.out.printf("Hello %s, age %d\n", name, age);
读取独占一行的 int 或 double 值时,经常需要使用技巧:先读取数字,再读取当前行余下的全部内容(仅仅是一个换行符)。
