正确读取TXT词库应使用BufferedReader按行读取后用split("s+", 2)切分并trim,二分查找前须用Collections.sort()严格升序排序且仅一次,查询时只判idx>=0,中文显示需显式指定UTF-8编码。

读取TXT词库时别用Scanner.nextLine()逐行吃空格
很多初学者一上来就用 Scanner 配合 nextLine() 读词库,结果遇到“apple 苹果”这种带空格的条目直接劈成两半——next() 停在第一个空格,nextLine() 又可能吞掉换行导致错位。本质是没分清分隔符和语义边界。
正确做法是按行读完整字符串,再用固定分隔符切分,且要容忍前后空格:
String line = bufferedReader.readLine();
if (line != null && !line.trim().isEmpty()) {
String[] parts = line.split("\s+", 2); // 最多切2段:英文+剩余(含中文)
if (parts.length == 2) {
String en = parts[0].trim();
String cn = parts[1].trim();
dict.add(new Word(en, cn));
}
}- 用
BufferedReader替代Scanner,避免缓存和分词干扰 -
split("\s+", 2)中的2很关键:只切第一处空白,保留中文里的空格(如“苹果 pie”) - 务必
trim()每段,TXT里常见行首缩进或行尾空格
二分查找前必须保证List按英文单词严格升序
Java 的 Collections.binarySearch() 不会帮你排序,传进去乱序列表只会返回负数,而且这个负数不是“没找到”,而是“插入点”的编码值,容易误判为查到了。
排序本身也有坑:直接 String.compareTo() 在中英文混排时可能不符合预期(比如大小写、撇号、连字符),但词典场景下你只要保持和录入顺序一致即可,不用过度优化排序规则。
立即学习“Java免费学习笔记(深入)”;
- 录入完所有词后,**必须且只能调一次**
Collections.sort(dict, Comparator.comparing(w -> w.en)) - 不要在每次查询前都排序——那是 O(n log n),比线性扫描还慢
- 如果词库不变,排序可放在初始化阶段;若支持热加载,记得加锁或重建整个列表
binarySearch返回负值不等于“没找到”
查 "zebra" 返回 -5,不代表它不存在,而是说“应该插在索引 4 的位置”。直接拿这个负值当 false 用,逻辑就断了。
标准判断姿势只有一行:
int idx = Collections.binarySearch(dict, target, Comparator.comparing(w -> w.en));
if (idx >= 0) { /* 找到了,dict.get(idx) 就是结果 */ }- 只看
idx >= 0,其余情况一律视为未命中 - 别试图从负值里还原插入点——除非你要做模糊匹配或联想,那已超出“简单词典”范围
- 注意:
binarySearch要求比较器和排序时用的是同一套逻辑,否则行为未定义
中文显示乱码?问题大概率出在文件编码没指定
Windows 记事本默认存为 GBK,而 Java FileReader 默认用平台编码(Win上就是GBK),但如果你用 VS Code 或 IntelliJ 新建TXT,很可能存成 UTF-8。两边对不上,中文就变“? ? ?”。
解决方法不是改编辑器设置,而是代码里明确声明编码:
InputStream is = new FileInputStream("dict.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));- 永远用
InputStreamReader+ 显式编码名,别碰FileReader - 如果不确定词库编码,先用命令行查:
file -i dict.txt(Linux/macOS)或用 VS Code 底部状态栏看当前编码 - 一旦选错编码,
readLine()读出来的字符串已经损坏,后面怎么处理都白搭
二分查找快是快,但前提是数据干净、顺序对、编码稳——这三个点任何一个松动,性能优势立刻归零,还多出一堆隐性 bug。










