stream.flatmap实现词频统计与特征词提取的核心是“先拆开、再聚合、最后筛选”:先用flatmap将文本流扁平化为单词流,再用groupingby+counting统计频次,最后过滤停用词、设阈值并排序取top-n。

用 Stream.flatMap 做词频统计和特征词提取,核心在于“先拆开、再聚合、最后筛选”。它不直接统计,而是把原始文本流变成单词流,为后续分组、计数、过滤打下基础。关键不是 flatMap 本身,而是它如何衔接整个处理链。
拆分句子为单词流:flatmap 的不可替代作用
一段文本(比如多行字符串或句子列表)天然是嵌套结构:一行 → 多个词。map 只能一对一转换,无法把一行变多个词;flatMap 则能对每行执行 split(" ") 得到单词数组,再转成子流,最终合并为扁平的单词流。
- 输入是
Stream<string></string>(每行一个字符串) -
.flatMap(line -> Arrays.stream(line.split("\s+")))把每行按空白符切分,并展平 - 输出是
Stream<string></string>(所有单词,无嵌套) - 注意正则
"\s+"比单空格更健壮,可处理制表符、连续空格等
统计词频:groupingBy + counting 是标准组合
拿到扁平单词流后,用 Collectors.groupingBy 按单词本身分组,下游用 Collectors.counting() 累计次数,一步生成 Map<string long></string>。
.collect(Collectors.groupingBy(word -> word, Collectors.counting()))- 默认区分大小写,如需忽略,统一转小写:
word.toLowerCase() - 结果是无序的,如需按频次排序,后续加
entrySet().stream().sorted(...)
提取特征词:在统计后加过滤与排序逻辑
特征词 ≠ 所有词,通常指高频、有区分度、非停用词的词汇。这步发生在 collect 之后,属于流式后处理:
- 排除停用词:提前准备 Set
stops = Set.of("the", "a", "an", "in", "on"); 过滤时加 .filter(e -> !stops.contains(e.getKey())) - 设最低频次阈值:如只取出现 ≥ 5 次的词,用
.filter(e -> e.getValue() >= 5) - 按频次降序取 Top-N:
.sorted(Map.Entry.<string long>comparingByValue().reversed()).limit(10)</string> - 最终可转为 List
(仅词)、List (词+频次),或封装为自定义对象
处理大规模文本的实用建议
面对大文件或高吞吐场景,光靠单机 Stream 不够,需兼顾性能与健壮性:
- 用
Files.lines(Paths.get("file.txt"))替代手动 BufferedReader,自动资源管理且支持懒加载 - 加
.parallel()可提速,但注意:split 和 groupingBy 在并行下仍线程安全,但需确保 key 的 hash 一致(如全小写) - 避免内存溢出:不一次性 collect 全量 Map,可用
forEach或分批处理;或结合Collectors.toConcurrentMap提升并发写入效率 - 预处理很重要:去标点(
replaceAll("[^\w\s]", ""))、去数字、处理缩写(won't → will not)应在 flatMap 前或其中完成











