用竞赛在线评判系统(OJ)编程时,如果要从标准输入(System.in)读入的数据量非常大,使用Scanner类虽然简单,但效率可能偏低,因而可能导致程序超时或内存占用过大。此时可以尝试改用带缓冲的BufferedReader类读取数据以提高效率,而且数据量越大,差异越明显。
BufferedReader的readLine()方法和Scanner的nextLine()方法用法类似,都是读取并返回一行String类型字符串,以回车做结束符。当需要从一行字符串中提取基本类型数据时,例如以空格分隔的数组元素,可以先用String类的split(" ")方法将字符串分割成子串数组,再用包装类Integer(或Double)的parseInt()(或parseDouble())方法将每个子串解析为基本类型数据。
需要注意的是,使用字符流BufferedReader从字节流System.in读取数据时,需要先用System.in做参数创建转换流InputStreamReader对象(从字节到字符的桥梁),再用此对象做参数创建BufferedReader对象。
以下程序从键盘读取并显示一个200*200的整数数组,每个数介于0~10000之间。用OJ系统(来自http://www.educg.net/index.html)录入相同的数据,分别测试使用Scanner和BufferedReader两个类时程序运行时间和占用内存的差异。
import java.util.Scanner;
import java.io.*;
public class InputTest {
/**
* Used to randomly generate an m*n array for test
*/
public static void generate(int m, int n) {
int[][] array = new int[m][n];
int i, j;
for (i = 0; i < m; ++i) {
for (j = 0; j < n; ++j) {
array[i][j] = (int) (Math.random() * 10000);
}
}
printArray(array);
}
public static int[][] TestScanner(int m, int n) {
Scanner scan = new Scanner(System.in);
String input, s[];
int[][] array = new int[m][n];
int i, j;
for (i = 0; i < m; ++i) {
input = scan.nextLine();
s = input.split(" "); //split string
for (j = 0; j < n; ++j) {
array[i][j] = Integer.parseInt(s[j]);
}
}
return array;
}
public static int[][] TestBufferedReader(int m, int n) throws IOException {
String input, s[];
int[][] array = new int[m][n];
int i, j;
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
for (i = 0; i < m; ++i) {
input = br.readLine();
s = input.split(" "); //split string
for (j = 0; j < n; ++j) {
array[i][j] = Integer.parseInt(s[j]);
}
}
br.close();
return array;
}
public static void printArray(int[][] array) {
int i, j;
for (i = 0; i < array.length; ++i) {
for (j = 0; j < array[i].length; ++j) {
System.out.print(array[i][j] + " ");
}
System.out.println();
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException {
//generate(200,200);
int option = 0; //0: Scanner; 1: BufferedReader
int m = 200,n = 200;
int[][] array;
switch (option) {
case 0:
array = TestScanner(m, n);
break;
default:
array = TestBufferedReader(m, n);
break;
}
printArray(array);
}
}
当option = 0时,使用Scanner的测试结果:
当option = 1时,使用BufferedReader的测试结果:
多次测试结果表明,数据量较大时,BufferedReader比Scanner读取数据的效率更高。但因为使用BufferedReader涉及异常处理以及多个输入流的创建和套接,内存开销未必会比Scanner更小。