两个版本的 Scanner 之间有什么区别?
What are the differences between two versions of Scanner?
这些从控制台读取输入的方式有什么区别?
Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
和
Scanner in = new Scanner(new BufferedInputStream(System.in));
以及优缺点是什么?
我认为回答这些问题的最好方法是检查实际实现的源代码。您可以从这里下载源代码:http://download.java.net/openjdk/jdk8/ 或只是 Google 具体 类:"java.util.Scanner source".
在这种情况下匹配源:
public Scanner(InputStream source) {
this(new InputStreamReader(source), WHITESPACE_PATTERN);
}
您可以使用这段代码实现同样的效果:
Scanner in = new Scanner(new BufferedReader(new InputStreamReader(new BufferedInputStream(System.in))));
Scanner
构造函数
就目前的情况而言,没有太大区别。
您使用的 Scanner
的第一个构造函数 Scanner(Readable)
将一个对象作为参数,该对象表示 字符 的传入序列,可以是使用 CharBuffer
.
阅读
您使用的 Scanner
的第二个构造函数 Scanner(InputStream)
将一个对象作为参数,该对象表示 字节 .[=38 的传入序列=]
需要强调的是字节不是字符。根据字符编码,字符可能由不同的字节序列表示,并且每个字符可能跨越多个字节。
在内部,第二个构造函数立即用 InputStreamReader
包装参数 - 这是一个 Readable
提供字符数据,因此它几乎与使用第一个构造函数相同。
BufferedInputStream
对比 BufferedReader
所以剩下的区别是
new BufferedReader(new InputStreamReader(System.in))
和
new InputStreamReader(new BufferedInputStream(System.in));
它们读取数据的方式略有不同。
每次需要输入时,第一个链将填充 8192 个字符的缓冲区,从底层 reader 获取每个字符,后者将从System.in
.
字节
每次需要输入时,第二条链将填满 8192 字节 的缓冲区。因此,当包装 reader 需要下一个字符时,假设该字符在输入中由两个字节表示,而当前缓冲区中只有该字符的一个字节。第二个字节将需要再次填充缓冲区。
我没有经验数据,但我认为鉴于 Scanner
本身每次需要数据时都会填充一个 CharBuffer
,所以上述细微差别将是微不足道的。事实上,我相信您可以安全地放弃使用 BufferedReader
或 BufferedInputStream
,而只需将 InputStreamReader
或 System.in
直接提供给 Scanner
,这将花费注意缓冲。
指定输入的字符集
如果您需要使用特定字符集进行输入,会有所不同。例如,如果您想确保传入的字节流被解释为 UTF-8
,您可以使用:
Scanner in = new Scanner(new InputStreamReader(System.in,StandardCharsets.UTF_8));
否则,输入字节将被解释为您的默认字符集,该字符集不一定是 UTF-8
。
Scanner
的另一个构造函数也允许使用普通 InputStream
:
Scanner in = new Scanner(System.in, "UTF-8");
这也将立即用 InputStreamReader
换行 System.in
,所以差别不大。
这些从控制台读取输入的方式有什么区别?
Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
和
Scanner in = new Scanner(new BufferedInputStream(System.in));
以及优缺点是什么?
我认为回答这些问题的最好方法是检查实际实现的源代码。您可以从这里下载源代码:http://download.java.net/openjdk/jdk8/ 或只是 Google 具体 类:"java.util.Scanner source".
在这种情况下匹配源:
public Scanner(InputStream source) {
this(new InputStreamReader(source), WHITESPACE_PATTERN);
}
您可以使用这段代码实现同样的效果:
Scanner in = new Scanner(new BufferedReader(new InputStreamReader(new BufferedInputStream(System.in))));
Scanner
构造函数
就目前的情况而言,没有太大区别。
您使用的 Scanner
的第一个构造函数 Scanner(Readable)
将一个对象作为参数,该对象表示 字符 的传入序列,可以是使用 CharBuffer
.
您使用的 Scanner
的第二个构造函数 Scanner(InputStream)
将一个对象作为参数,该对象表示 字节 .[=38 的传入序列=]
需要强调的是字节不是字符。根据字符编码,字符可能由不同的字节序列表示,并且每个字符可能跨越多个字节。
在内部,第二个构造函数立即用 InputStreamReader
包装参数 - 这是一个 Readable
提供字符数据,因此它几乎与使用第一个构造函数相同。
BufferedInputStream
对比 BufferedReader
所以剩下的区别是
new BufferedReader(new InputStreamReader(System.in))
和
new InputStreamReader(new BufferedInputStream(System.in));
它们读取数据的方式略有不同。
每次需要输入时,第一个链将填充 8192 个字符的缓冲区,从底层 reader 获取每个字符,后者将从System.in
.
每次需要输入时,第二条链将填满 8192 字节 的缓冲区。因此,当包装 reader 需要下一个字符时,假设该字符在输入中由两个字节表示,而当前缓冲区中只有该字符的一个字节。第二个字节将需要再次填充缓冲区。
我没有经验数据,但我认为鉴于 Scanner
本身每次需要数据时都会填充一个 CharBuffer
,所以上述细微差别将是微不足道的。事实上,我相信您可以安全地放弃使用 BufferedReader
或 BufferedInputStream
,而只需将 InputStreamReader
或 System.in
直接提供给 Scanner
,这将花费注意缓冲。
指定输入的字符集
如果您需要使用特定字符集进行输入,会有所不同。例如,如果您想确保传入的字节流被解释为 UTF-8
,您可以使用:
Scanner in = new Scanner(new InputStreamReader(System.in,StandardCharsets.UTF_8));
否则,输入字节将被解释为您的默认字符集,该字符集不一定是 UTF-8
。
Scanner
的另一个构造函数也允许使用普通 InputStream
:
Scanner in = new Scanner(System.in, "UTF-8");
这也将立即用 InputStreamReader
换行 System.in
,所以差别不大。