streamtokenizer从system.in读取输入时不会自动结束,必须手动发送eof信号(linux/macos按ctrl+d,windows按ctrl+z)才能退出循环,否则将无限等待输入。
StreamTokenizer 本身并不“感知”用户何时停止输入——它只是持续从底层 Reader 中读取字符,直到遇到真正的流结束(EOF)。而 System.in 对应的标准输入流在程序运行期间始终处于打开状态,除非用户显式触发终端级 EOF 信号,否则 st.nextToken() 永远不会返回 st.TT_EOF,导致 while 循环卡住。
例如以下代码看似合理,实则存在阻塞风险:
import java.io.*;
import java.util.ArrayList;
public class ConsoleTokenReader {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer st = new StreamTokenizer(br);
st.parseNumbers(); // 显式启用数字解析(推荐)
ArrayList numbers = new ArrayList<>();
while (st.nextToken() != StreamTokenizer.TT_EOF) {
if (st.ttype == StreamTokenizer.TT_NUMBER) {
numbers.add(st.nval); // 正确:st.nval 是 double 类型
}
}
System.out.println("Read " + numbers.size() + " numbers: " + numbers);
br.close();
}
} ⚠️ 关键注意事项:
? 替代建议(更现代、更可控):
对于控制台交互场景,推荐使用 Scanner 替代 StreamTokenizer,语义更直观且支持灵活的终止条件:
import java.util.*;
public class ScannerBasedReader {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
List nums = new ArrayList<>();
System.out.println("Ent
er integers (press Ctrl+D/Ctrl+Z to finish):");
while (sc.hasNextInt()) {
nums.add(sc.nextInt());
}
System.out.println("Collected: " + nums);
sc.close();
}
} 总结:StreamTokenizer 的 TT_EOF 依赖底层流的真实结束,控制台输入需人工触发 EOF;理解这一机制是避免无限等待的关键。在实际开发中,优先考虑 Scanner 或 BufferedReader.readLine() + 字符串解析,兼顾可读性与可控性。