【发布时间】:2015-10-20 23:05:07
【问题描述】:
这些从控制台读取输入的方式有什么区别?
Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
和
Scanner in = new Scanner(new BufferedInputStream(System.in));
还有什么优点和缺点?
【问题讨论】:
这些从控制台读取输入的方式有什么区别?
Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
和
Scanner in = new Scanner(new BufferedInputStream(System.in));
还有什么优点和缺点?
【问题讨论】:
Scanner 构造函数就这些电话而言,差别不大。
您使用的Scanner 的第一个构造函数Scanner(Readable) 将一个对象作为参数,该对象表示传入的字符 序列,可以使用CharBuffer 读取。 p>
您使用的Scanner 的第二个构造函数Scanner(InputStream) 将表示传入字节序列的对象作为参数。
需要强调的是字节不是字符。根据字符编码的不同,字符可能由不同的字节序列表示,并且每个字符可能跨越多个字节。
在内部,第二个构造函数立即用InputStreamReader 包装参数 - 这是一个提供字符数据的Readable,因此它与使用第一个构造函数几乎相同。
BufferedInputStream 与 BufferedReader
所以剩下的区别就是
new BufferedReader(new InputStreamReader(System.in))
和
new InputStreamReader(new BufferedInputStream(System.in));
它们在读取数据的方式上略有不同。
每次需要输入时,第一个链将填充 8192 个 字符 的缓冲区,从底层读取器获取每个字符,该读取器将从 System.in 的字节中解释它。
每次需要输入时,第二个链将填充 8192 个 字节 的缓冲区。因此,当包装阅读器需要下一个字符时,假设该字符由输入中的两个字节表示,并且该字符中只有一个字节在当前缓冲区中。第二个字节需要再次填充缓冲区。
我没有经验数据,但我认为鉴于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");
这也将立即将System.in 与InputStreamReader 包装起来,所以差别不大。
【讨论】:
Scanner 仅具有 1024 个字符的缓冲区,添加 Buffered... 会添加 8192 个字符/字节的底层缓冲区。因此,如果您正在读取大量数据(例如文件),则会有所不同,但是如果您正在读取较小的输入(例如控制台输入),我认为没有优势
我认为回答这些问题的最佳方法是检查实际实现的来源。你可以从这里下载源代码:http://download.java.net/openjdk/jdk8/ 或者只是谷歌特定的类:“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))));
【讨论】: