StreamTokenizer简单介绍
StreamTokenizer是Java中的一个类,用于将输入流(比如文件或者字符串)分解为词法单元(tokens)。它可以识别不同类型的词法单元,如数字、字符串、标识符、运算符等,并将它们以相应的类型进行分类。在处理文本文件或解析简单的文本格式时,StreamTokenizer非常有用。
StreamTokenizer提供了一种简单而有效的方法来读取和解析输入流,它具有灵活性和高效性,可以适应各种输入源的需要。通过逐个读取输入流中的字符,并根据字符的类型将其组合成不同类型的词法单元,StreamTokenizer使得文本解析变得更加方便和直观。
StreamTokenizer读取Java int范围内的整形
对于StreamTokenizer,使用他的nextToken()方法读取一个单词,使用StreamTokenizer对象的nval属性来获取单词,但是由于nval属性为double类型,需要使用(int)强制类型转换。
读取代码:
public class FastInputInt {
/**
* 构建最快的StreamTokenizer对象
*/
public static final StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
/**
* 封装的读取整数方法
*
* @return 读取的整数
*/
public static int readInt() {
try {
// 固定写法
st.nextToken();
return (int) st.nval;
} catch (Exception ignored) {
// 忽略异常
}
return -1;
}
public static void main(String[] args) {
// 测试输入StreamTokenizer快速读取 n 个数据
int n = readInt();
// 申请内存
int[] data = new int[n];
for (int i = 0; i < n; i++) {
// 为数组赋值
data[i] = readInt();
}
// 数据接收完毕, 使用Arrays.toString()查看数组的内容
System.out.println(Arrays.toString(data));
}
}
使用上方代码,可以读取下面类型的控制台输入
10
1 2 3 4 5 6 7 8 9 10
或
10
1
2
3
4
5
6
7
8
9
10
下面为测试截图,可以看到数组内容为刚刚在控制台输入的数字
StreamTokenizer读取Java long范围内的整形
因为StreamTokenizer读取的数字类型会被存入一个类型为double,变量名为nval的变量中,也就是说,这个数字会受到double类型精度的影响,不能精确的存储long范围内的值,所以我们需要使用StreamTokenizer读取“数字字符串”,然后使用Long.parseLong()方法把这个读取到的字符串转为long。
我们可以调用StreamTokenizer对象的ordinaryChars('0','9')和wordChars('0','9')方法修改StreamTokenizer对象分隔单词的规则,使得'0'到'9'的字符不再识别为数字。
调用nextToken()方法后,读取StreamTokenizer对象的sval属性就可以拿到数字字符串。
读取long的代码:
public class FastInputLong {
/**
* 构建最快的StreamTokenizer对象
*/
public static final StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
// 静态方法,配置StreamTokenizer
static {
// 为StreamTokenizer配置, 把 0 - 9 当成字符串识别
st.ordinaryChars('0', '9');
st.wordChars('0', '9');
}
/**
* 封装的方法
*
* @return 读取的整数
*/
public static long readLong() {
try {
// 固定写法
st.nextToken();
return Long.parseLong(st.sval);
} catch (Exception ignored) {
// 忽略异常
}
return -1;
}
public static void main(String[] args) {
// 因为java数组最大长度不超过int最大值, 所以这里需要强制转为int让编译通过
int n = (int) readLong();
long[] data = new long[n];
for (int i = 0; i < n; i++) {
data[i] = readLong();
}
System.out.println(Arrays.toString(data));
}
}
测试输入以下案例
10
1 2 3 4 5 6 7 8 9 10
运行结果:
测试读取大一点的整数,9223372036854775807为java long最大值
10
1000000000000000000
1111111111111111111
2222222222222222222
3333333333333333333
4444444444444444444
5555555555555555555
6666666666666666666
7777777777777777777
8888888888888888888
9223372036854775807
输出:
我们再来测试一下如果不读取数字字符串,而是直接使用long val = st.nval;读取,看看会读取到什么内容。
public class DoubleReadTest {
public static final StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
public static void main(String[] args) throws IOException {
st.nextToken();
int n = (int) st.nval;
long[] data = new long[n];
for (int i = 0; i < n; i++) {
st.nextToken();
data[i] =(long) st.nval;
}
for (long l : data) {
System.out.println(l);
}
}
}
测试结果如下,可以看到输出的值与输入的值不同,存在精度问题,所以我们在要读取long范围内的数字时需要先读取到数字字符串再通过Long.parseLong()进行转换。