文本输入和输出
我们都知道,使用System.out.print 和 System.out.println 函数可以很轻易地显示文本给用户。但是,在文本输出这个主题上还有很多知识是我们要知道的。此外,很多程序都会使用运行时输入的数据,所以你同样需要知道怎样输入数据。本节讲解了如何从用户里获取数据,比之前更详细地讲解文本输入。本节也会涉及到使用文件进行输入和输出。
2.4.1 基本输出以及格式化输出
最基本的输出函数就是 System.out.print(x),这里的 x 可以是一个值或者任意类型的表达式。如果这里的 x 参数不是字符串,它会被转换为字符串类型,然后就会把这个字符串输出到标准输出里。(通常,这意味着这个字符串会显示给用户;然而在 GUI 程序里,会把这个字符串输出到一般用户看不到的地方。此外,可以把标准输出“重定向”写到另一个不同的目标上。不过,对于我们现在用以学习的程序来说,使用 System.out 的主要目的是向用户输出文本。)
System.out.println(x) 与 System.out.print 输出的文本是一样的,不过 println 会在文本后追加一个换行符,这意味着之后的任何输出都会输出到下一行。也可以在使用这个函数时不提供参数,此时的 System.out.println() 只会输出一个换行符。要注意的是,System.out.println(x) 等价于
1
2System.out.print(x);
System.out.println();
你可能已经注意到了,System.out.print 在输出实数时会输出尽可能多的小数位。因此,π 的输出为 3.141592653589793,代表金钱的数字的输出可能是 1050.0 或者 43.575 。但你可能更喜欢看到这些数字的输出是这样的:3.14159, 1050.00 和 43.58 。Java有一个“格式化输出”功能,它可以轻易地控制实数和其他数值的输出格式。格式化选项有很多,我在这仅讲解一些简单的和最常用的选项。
System.out.printf 函数可以产生格式化输出。(代表“格式化输出”的“printf”函数名模仿了 C 和 C++ 语言的输出函数,也就是说这种类型的输出起源与C和C++。)System.out.printf 函数需要一个或者多个参数。第一个参数指定了输出格式的字符串参数。这个参数叫做格式化字符串。其余的参数指定了要输出的数值。这里有个以合适格式输出金额数值的语句,这里的 amount 是一个 double 型的变量:
1System.out.printf('%1.2f', amount );
数值的输出格式由格式说明符来指定。在这个例子中,格式说明符为 %1.2f 。(我这里提到的简单例子的)格式化字符串包含了一个格式说明符,为每个要输出的值指定了格式。一些典型的格式说明符有 %d, %12d、 %10s、 %1.2f、 %15.8e 和 %1.8。每个格式说明符都以一个百分号(%)开始并以一个字母结束,中间可以带有一些额外的格式化信息。这里的字母指定了要处理的输出类型。例如 %d 和 %12d,字母“d”指定了输出的类型是一个整数。%12d 里的“12”指定了用来显示输出的最小位数。如果输出的整数少于 12 位,那么就会在这个整数前添加额外的空位来填满 12 位。我们把这种情况叫做“在长度为 12 的字段里向右对齐” 。一个比较大的数值不一定是 12 位的。如果这个数值超过 12 位,所有的数位都会被打印输出,不会有额外的位数填充。%d 说明符等价于 %1d ——以尽可能多的数位来输出整数。(顺便说明下,“d”代表着“十进制”数字。你可以使用“x”代替“d”来以十六进制的格式输出一个整数。)
以“s”字母结束的格式化说明符可以用来输出任意类型的值。这意味着,这个数值将以默认的格式输出,与非格式化输出一样。类似于 %20s 中的“20”,可以添加一个数字来指定字符的(最小)数量。“s”代表着”字符串“,可以用于字符串类型。同样也可以用于其他类型的值,但在这种情况下,通常是把这个值转换为字符串类型的值。
double 类型的格式化说明符比较复杂。就像 %1.2f 中的“f”,它用于以“浮点数”形式输出数字,这个数字的小数点后还带有数位。在 %1.2f 中,“2”指定了小数点后的使用位数。“1”指定输出的(最小)字符;这个位置的“1”实际上意味着,使用尽可能多的字符。类似地,%12.3f 会指定一个在小数点后带有 3 位小数的浮点格式,并在长度为 12 的字段里向右对齐。
比较大和比较小的数字应该以指数格式打印,比如 6.00221415e23 代表“6.00221415 乘以 10 的 23 次幂“。像 %15.8e 这样的格式说明符指定了以指数的形式输出,”8“表明了要在小数点后使用 8 个数位。如果你使用”g“代替”e“,那么会以指数形式输出比较小和比较大的数值,以浮点格式来输出其他的数值。在 1.8g 中,”8“指定了总的位数,它包括小数点前的位数以及小数点后的位数。
对于数值输出,格式说明符可以包含一个逗号(“,”),它会把数字的数位分组提高数字的可读性。在美国,使用逗号把 3 个数位分为一组。例如,如果 x 的值为十亿,那么 System.out.printf(“%,d”, x) 会输出 1,000,000,000 。在其他的国家,分隔字符和每一组的数位可能会有所不同。逗号应该放在格式说明符的开始,在字符宽之前;例如,%,12.3f 。如果你想向左对齐输出数据而不是向右对齐输出,你可以在格式说明符的开始位置添加一个负号,比如 %-20s 。
除格式化说明符之外,printf 语句中的格式化字符串可以包括其他的字符。这些额外的字符会直接被复制到输出里。这使我们能够方便地在输出字符串中间插入数值。例如,如果 x 和 y 都是 int 类变量,你可以
1System.out.printf('The product of %d and %d is %d', x, y, x*y);
当执行这个语句时,x 的值会代替字符串中的第一个 %d,y 的值代替第二个 %d,表达式 x*y 的值会代替第三个 %d 。因此,上面语句的输出类似这样“The product of 17 and 42 is 714”(引号不包括在输出里!)
要输出百分号,需要在格式化字符串中使用格式化说明符 %% 。你可以使用 %n 来输出换行符。你同样也可以使用反斜杠 ,就像平时在字符串里输出制表符和双引号这些特殊字符一样。
2.4.2 第一个文本输入例子
由于一些莫名的原因,Java 读取用户的输入数据从来都不是一件轻松的事情。你已经知道,我们可以使用 System.out.print 子程序显示输出给用户。这个子程序是 System.out 预定义对象的一部分。这个对象的作用就是准确地把输出显示给用户。这里有一个相应的 System.in 对象,它的作用就是从用户里读取输入数据。但是它只提供了很基本的输入能力,要高效地使用它还需要一些高级的 Java 编程技巧。
在 Java 5.0 里提供了一个新的 Scanner 类让我们能够更容易地读取输入。然而,要使用这个类还需要一些面向对象编程的知识。因此,在这个课程的开始不太适合使用它。Java 6 引进了一个与用户交互的 Console 类,但是 Console 本身就有问题。(它并不总是可用的,它只能用来读取字符串,不能读取数字。) 此外在我看来,Scanner 和 Console 不是十分准确。即便如此,我还会在这节的后面简要的介绍下 Scanner,以便你现在就可以使用它。不过,我会实现自己的文本输入版本。
幸运的是,我们可以创建新的 Java 语言标准里没有提供的子程序来扩展 Java 。一旦新的类可以使用,这个类包含的子程序就可以像内置程序一样使用。按照这个特性,我写了一个命名为 TextIO 的类,这个类定义了读取用户输入值的子程序。这个类的子程序让我们能够直接从 System.in 标准输入对象里获取输入,而且不需要了解 Scanner 或者 System.in 这些高级的Java对象的使用方法。TextIO 还有一些其他的功能,我将会在这节的后面讨论它们。
要使用 TextIO 类,你必须要确保你的程序能够访问它。能否访问取决于你在使用的 Java 编程环境:你只需把 TextIO.java 的源码文件添加到与你的主程序相同的目录下。详情请看 2.6 节的如何使用 TextIO 。
TextIO 类的输入子程序都是静态成员函数。(静态成员函数在之前的章节里有介绍。)我们假设,你想在你的程序里读取一个用户输入的整数。TextIO 类就包含了一个名为 getlnInt 的静态成员变量来实现你的目的。由于这个函数包含在 TextIO 类里,因此你必须在你的程序里使用 TextIO.getlnInt 来引用它。这个函数没有任何参数,因此“TextIO.getlnInt()”的形式就是这个方法的完全调用。这个方法调用代表了用户输入的 int 值,所以你必须要处理这个返回值,比如把它赋值给一个变量。例如,如果用户输入是一个 int 型变量(使用“int userInput”声明语句创建),然后你就可以使用这个赋值语句了
1userInput = TextIO.getlnInt();
当计算机运行上面的语句时,它会等待用户输入一个整型数值。程序必须要等用户输入一个数字并且按下回车后才可以继续运行。然后函数就会返回用户输入的值,并且把它保存在 userInput 变量里。下面是一个完整的程序,它使用 TextIO.getlnInt 去读取一个用户输入的数并输出这个数的平方:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24/**
* A program that reads an integer that is typed in by the
* user and computes and prints the square of that integer.
*/
public class PrintSquare {
public static void main(String[] args) {
int userInput;// The number input by the user.
int square;// The userInput, multiplied by itself.
System.out.print('Please type a number: ');
userInput = TextIO.getlnInt();
square = userInput * userInput;
System.out.println();
System.out.println('The number that you entered was ' + userInput);
System.out.println('The square of that number is ' + square);
System.out.println();
}// end of main()
}//end of class PrintSquare
当你运行这个程序时,它会显现“Please type a number:”信息并且停下来等待你的输入信:包括一个数字和一个回车。注意,在读取输入之前向用户输出一个询问或者提示是一种很好的习惯。否则,用户无法知道计算机到底在等待什么,甚至不知道计算机是在等待用户的操作。
2.4.3 基本 TextIO 输入函数
TextIO 包含了很多用于读取各种类型值的函数。这里有一些你很有可能会用到的函数:
1
2
3
4
5
6j = TextIO.getlnInt();//读取一个 int 类型的值。
y = TextIO.getlnDouble();//读取一个 double 类型的值。
a = TextIO.getlnBoolean();//读取一个 boolean 类型的值。
c = TextIO.getlnChar();//读取一个 char 类型的值。
w = TextIO.getlnWord();//读取一个“单词”作为 String 类型的值。
s = TextIO.getln();//读取一整行作为一个字符串。
为了使上面的语句合法,每个赋值语句左边的变量必须都是已经声明的变量并且它们的类型要与右边的函数返回值的类型一致。要特别注意的是,这些函数都是没有参数的。它们的返回值都来自于程序外部,并且是程序运行时用户输入的值。要“捕获”这些数据用在你的程序里,你必须把这些函数的返回值赋值给一个变量。然后你就可以使用变量名来引用用户输入的值。
当你调用这些函数的其中一个的时候,它就会返回一个正确类型的合法值。如果用户输入一个非法的值——比如,你要求输入一个 int 值,而用户输入一个非数字的字符或者一个超出 int 类型的合法范围的数字——那么计算机会要求用户重新输入,而且你的程序不会看到用户之前的非法输入。对于 TextIO.getlnBoolean() ,它允许用户输入 true、fals、t、f、yes、no、y、1 或者 0。此外,这些字符可以是大写的或者小写的。在任何的情况下,用户的输入都被解析为一个 true/false 值。这便于使用 TextIO.getlnBoolean() 去读取用户的 Yes/No 答复。
这里有两个返回字符串的输入函数。第一个是 getlnWord(),它返回一个仅由非空字符组成的字符串。调用这个函数时,它会跳过所有的用户输入的空格和换行符。然后它会读取下一个空格或者换行符之前的所有非空字符。它会返回一个由所有已经读取的非空字符组成的字符串。第二个输入函数是 getln(),它简单地返回输入换行符之前输入的所有字符(包括空格)。这个函数获取了整行的输入文本,包括换行符。但是换行符本身不会作为输入字符串的一部分返回给程序,因为它会被计算机丢弃掉。要注意的是, TextIO.getln() 函数返回的字符串有可能是不包含任何字符的空字符串”'。如果用户只是简单的按了回车,没有输入其他的任何东西,那么你就会获取到这个返回值(空字符串)。
TextIO.getln() 在读取一个值之前不会跳过任何的空格和换行符。但是 getlnInt()、getlnDouble()、getlnBoolean() 和 getlnChar() 这些函数的行为与 getlnWord() 类似,在读取一个值之前,它们都会跳过所有的空格和换行符。当这些函数的其中一个跳过换行符时,都会输出一个“?”来提示用户进行更多的输入。
此外,如果用户在输入的值后面添加了一些额外的字符,那么所有的这些额外字符都会与行末的换行符一起被丢弃掉。如果程序还运行有另外一个输入函数,用户必须要在下一行进行输入,即使用户能够在上一行里输入了不止一个值。丢弃用户的输入看起来可能不是一个很好的方案,但是这个做法已经证明了它在大多数程序里是最安全的方案。
使用 TextIO 来进行输入和输出,我们现在可以来改进 2.2 节里的投资计算(computing the value of an investment)程序。我们可以让用户来输入投资的初始值和利率。这样我们就拥有了一个更有用的程序——原因之一是,可以重复利用这个程序!注意,这个程序使用格式化输出以合适的格式来输出货币值。
(你可能很好奇为什么这里只有一个输出子程序:能够输出任何类型值的System.out.println,而对每种数据类型却都有单独的输入程序。对于输出函数,计算机可以根据参数来确定要输出哪种类型的值。但是输入程序没有任何的参数,因此不同的输入程序只能通过使用的不同函数名来区分。)
2.4.4 文件 I/O 介绍
我们都知道 System.out 的输出目标是“标准输出”。但是标准输出仅是一个可能的输出目标而已。例如,数据可以被写到保存在用户硬盘里的文件里。这种做法有一些明显的优势:即使在程序结束后数据都会被保存在文件里、用户可以打印这个文件、把它发送邮件给其他人、使用其他的程序编辑它等待。类似地,System.in 仅拥有一个可能的输入源。
TextIO 能够把数据写到文件里和从文件里读取数据。TextIO 包括了 TextIO.put、TextIO.putln 和 TextIO.putf 这些输出函数。通常,这些函数的实际作用与 System.out.print,System.out.println,和 System.out.prinf 一样,并且可以互换使用。但是,它们同样可以用来把文件输出到文件里和其他的目标里。
当你使用 TextIO.put,TextIO.putln 或者 TextIO.putf 来进行输出时,会把输出发送到当前输出目标上。默认地,当前输出目标是标准输出。但是,你可以使用 TextIO 的子程序去更改当前输出目标。例如,你要写数据到名为“result.txt”的文件里,你可以使用这条语句:
TextIO.writeFile(“result.txt”);
运行这个语句后,TextIO 输出语句的所有输出都会被保存到名为“result.txt”的文件里而不是输出到标准输出里。如果没有这个文件就会创建一个这样的文件。注意,如果存在一个同名的文件,那么这个文件之前的内容都会被擦除而且不会有任何的警告!
当你调用 TextIO.writeFile 时,TextIO 会记住目标文件并且自动地把 TextIO.put 的所有输出或者其他函数的输出都保存到目标文件里。如果你想把输出数据写回标准输出里,你可以调用
TextIO.writeStandardOutput();
这里有一个简单的程序,它向用户询问了几个问题并把用户的回答保存到一个名为“profile.txt”的文件里。作为示例,这个程序使用了 TextIO 来把信息输出到标准输出和文件里。不过,System.out 同样也可以用来把信息输出到标准输出里。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41public class CreateProfile {
public static void main(String[] args) {
String name;// The user's name.
String email;// The user's email address.
double salary;// the user's yearly salary.
String favColor;// The user's favorite color.
TextIO.putln('Good Afternoon! This program will create');
TextIO.putln('your profile file, if you will just answer');
TextIO.putln('a few simple questions.');
TextIO.putln();
/* Gather responses from the user. */
TextIO.put('What is your name? ');
name = TextIO.getln();
TextIO.put('What is your email address? ');
email = TextIO.getln();
TextIO.put('What is your yearly income? ');
salary = TextIO.getlnDouble();
TextIO.put('What is your favorite color? ');
favColor = TextIO.getln();
/* Write the user's information to the file named profile.txt. */
TextIO.writeFile('profile.txt'); // subsequent output goes to file
TextIO.putln('Name: ' + name);
TextIO.putln('Email: ' + email);
TextIO.putln('Favorite Color: ' + favColor);
TextIO.putf( 'Yearly Income: %,1.2f%n', salary);
/* Print a final message to standard output. */
TextIO.writeStandardOutput();
TextIO.putln('Thank you. Your profile has been written to profile.txt.');
}
}
在很多情况下,你想让用户来选择保存输出的文件。你可以要求用户输入这个文件名,但是这种形式很容易出错。并且用户对从文件对话框里选择文件的形式更熟悉。语句
1TextIO.writeUserSelectedFile();
会打开一个典型的图形界面文件选择对话框让用户来选择输出文件。这也有利于在用户要覆盖一个已存在的文件时给用户发出警告。用户也可以在没有选择任何文件的情况下撤销对话选择框。TextIO.writeUserSelectedFile 函数会返回一个 boolean 值。如果用户选择了一个文件它就会返回 true ,如果用户撤销了对话选择框它就会返回 false 。如果程序需要知道是否要写入文件可以检查函数的返回值。
TextIO 可以从文件中读取,也可以从标准输入里读取。你可以为 TextIO 的各种“get”函数指定输入源。它们的默认输入源都是标准输入。你可以使用 TextIO.readFile(“data.txt”) 语句从名为“data.txt”的文件中读取,或者你可以使用 TextIO.readUserSelectedFile() 让用户从图形界面的对话选择框里选择输入文件。在你指定了输入文件后,所有的输入都会来自于指定的文件而不是用户来进行输入。你可以使用 TextIO.readStandardInput() 再次从标准输入里读取用户输入。
当你的程从标准输入里读取时,用户可以修正它的输入里的错误。而在从文件中读取的形式里,这是不可能的事情。如果程序在尝试从文件中读取数据时发现了非法的数据,那么就产生一个使程序崩溃的错误。(稍后我们会知道,我们可以“捕获”并修复这样的错误)在写入文件时尽管很少产生错误,但还是会有错误产生的。
要完全理解 Java 的输入和输出需要面向对象编程的知识。我们会在 11 章里重返这个话题。相比之下,TextIO 里的文件 I/O 功能是相对简单的。不过,它们对很多应用来说已经够用了,而且它们使你能够尽早地体验文件的操作。
2.45 其他的TextIO 特性
目前我们看到的 TextIO 输入函数仅能从一个输入行里读取一个值。但有的时候,你想在同一个输入行里读取不止一个值。例如,你可能想让用户能够输入一些类似于“42 17”这样的数据并在同一行里输入它们。为了让你能够实现这个功能,TextIO 提供了以下一些可选的输入函数:
j = TextIO.getInt(); //读取一个 int 类型的值。
y = TextIO.getDouble(); //读取一个 double 类型的值
a = TextIO.getBoolean(); //读取一个 boolean 类型的值
c = TextIO.getChar(); //读取一个 char 类型的值
w = TextIO.getWord(); //读取一个“单词”作为字符串类型的值。
这些函数的函数名以“get”开头而不是“getln”。”Getln“是”get line“的简写,因此,函数名以”getln“开头的函数会读取整行的数据。没有”ln“的函数将会以同样的方式读取一个值,并且会把输入行里的剩余数据保存在一个叫做输入缓冲区(input buffer)的内部内存块里。下一次计算机要读取一个输入值时,它会在提示用户进行输入之前去输入缓存区里查找数据。这使计算机能够从用户输入行里读取多个值。严格来说,计算机实际上只会从输入缓冲区里读取数据。程序第一次尝试读取用户输入时,计算机会等待用户输入整行的数据。TextIO 把这行输入都保存在输入缓冲区里,直到整行的数据都被读取完或者被丢弃(通过其中一个”getln“函数来实现)。用户只需在缓冲区为空时进行输入。
要注意的是,尽管 TextIO 输入函数在寻找输入数据时会跳过空格和换行符,但它们不会跳过其他的字符。例如,如果你要读取两个 int 数值并且用户输入了”42,17“,那么计算机将会正确地读取到第一个数字。但是在读取第二个数字时,它读取到输入里的逗号。然后它会认为这是一个错误的输入并且强制用户重新输入数字。如果你想在一行里输入多个数字,你需要确保用户知道要使用空格把它们隔开,而不是使用逗号。或者,如果想要在数字之间使用逗号,可以在读取第二个数字之前使用 getChar() 函数去读取逗号。
这里还有一个字符输入函数 TextIO.getAnyChar(),它不会跳过任何的空格和换行符。它只是简单地读取并返回下一个用户输入的字符,即使它是一个空格或者换行符。如果用户输入一个换行符,那么 getAnyChar() 会返回一个特殊的换行符”n“。这里还有一个 TextIO.peek() 函数,它可以让程序在没有真正读取下一个字符之前就可以知道这个字符是什么。在你”窥视“了下一个字符后,当你要从输入里读取下一个字符时它依然存在缓冲区里。这让你可以提前知道输入里的内容,以便你可以根据输入里的内容来采取不同的行为。
TextIO 类还提供了大量的其他的函数。要了解更多,你可以查看 TextIO.java 源码文件里的注释。
显然,输入的语义比输出的语义更复杂!但幸运的是,对于大多数应用来说,实践中的输入都很简单。如果你想实现一些复杂的输入,你仅需要了解其中的细节。特别地,我强烈建议你使用“getln”版本的输入程序,而不是使用“get”版本的,除非你真的想在同一输入行里读取多个条目。使用它的主要原因是,“getln”版本的语义更加简单。
2.4.6 使用 Scanner 读取输入
TextIO 让程序能够轻松地读取用户输入。但它不是一个标准的类,因此你一定要记得确保使用它的程序能够访问 TextIO.java 。获取输入的另外一种方法就是使用 Scanner 类。使用 Scanner 的一个优势是,它本身就是 Java 的一部分,因此你能够在任何你想使用它的地方调用它。
使用 Scanner 来读取用户输入并不困难,并且它有一些很棒的特性。不过,使用它需要一些第 4 章和第 5 章才介绍的语法。我会在这里告诉你怎么使用它,但不会解释它的工作原理。现在你不需要理解它的所有语法。(我们将会在 11.1.5 节里详细地介绍 Scanner )
首先,你需要在源代码文件里的“public class…”之前添加以下的代码:
1import java.util.Scanner;
然后在你的 main() 子程序的开头添加以下语句:
1Scanner stdin =new Scanner( System.in );
上面的语句创建了一个名为 sdtin 的 Scanner 类型变量。(如果你想,也可以使用不同的变量名;这里的“stdin”代表着“标准输入“。)然后你可以在你的程序里使用 stdin 去调用各种用来读取用户输入的子程序。例如,stdin.nextInt() 函数从用户里读取一个 int 类型的值并且把它返回。它与 TextIO.getInt() 很类似,除了这两点:如果用户输入的值不是一个合法的 int ,那么 stdin.nextInt() 会崩掉而不是提示用户重新输入;并且,用户输入的整数后面必须跟着一个空格或者一个换行符,而 TextIO.getInt() 在读取到非数字字符时会停止读取。
这里还有一些相应的方法用来读取其他类型数据的方法,包括 stdin.nextDouble(),stdin.nextLong(),和 stdin.nextBoolean()(stdin.nextBoolean() 只接收“true”或者“false”输入)。这些子程序都可以读取一行中的多个值,因此相对于 TextIO 的“getln”版本子程序,它们与“get”版本的子程序更相似。stdin.nextLine() 方法等价于 TextIO.getln(); stdin.next() 类似于 TextIO.getWord(),会返回一个非空字符串。
作为一个简单的示例,这里有一个 Interest2.java 简单程序的示例版本,它使用 Scanner 代替 TextIO 来读取用户输入:
import java.util.Scanner;// Make the Scanner class available.
public class Interest2WithScanner {
public static void main(String[] args) {
Scanner stdin =new Scanner( System.in );// Create the Scanner.
double principal;// The value of the investment.
double rate;// The annual interest rate.
double interest;// The interest earned during the year.
System.out.print('Enter the initial investment: ');
principal = stdin.nextDouble();
System.out.print('Enter the annual interest rate (as a decimal): ');
rate = stdin.nextDouble();
interest = principal * rate;// Compute this year's interest.
principal = principal + interest;// Add it to principal.
System.out.printf('The amount of interest is $%1.2f%n', interest);
System.out.printf('The value after one year is $%1.2f%n', principal);
}// end of main()
}// end of class Interest2With Scanner
注意,上面的程序多出的两行用来导入 Scanner 和创建 stdin。同样要注意的是 stdin.nextDouble() 子程序代替了 TextIO.getlnDouble()。(实际上,真正与 stdin.nextDouble 等价的是 TextIO.getDouble 而不是”getln“版本的子程序。但是这不会影响程序的行为,因为它只要求用户在一个输入行里输入一个数字。)
虽然目前我还会继续使用 TextIO 来读取输入。但是我会在每章课后习题的线上答案里给出更多的使用 Scanner 的例子。并且在这本书的后面还会有更多的详细的 Scanner 介绍。