Java如何实现按空格触发的控制台逐词读取?
在Java中实现逐词读取控制台输入(按空格触发)
当然可以实现!你遇到的Scanner局限很正常——它依赖输入缓冲区的换行来触发读取动作,所以必须等用户按下回车才会返回结果。要实现按下空格就立即读取此前输入的单词,我们需要直接操作底层的标准输入流,逐字符处理输入内容,自己控制单词的提交时机。
结合你提到的多线程项目背景(一个线程读输入、一个线程显示单词计数),下面是具体的实现方案:
核心思路
- 用
System.in.read()逐字符读取控制台输入,绕过Scanner的缓冲区限制 - 维护一个临时字符串,动态拼接用户输入的字符,直到遇到空格(或回车)
- 遇到分隔符时,将临时字符串作为单词存入线程安全的集合(因为多线程共享数据必须保证线程安全)
- 显示线程定期读取集合内容,输出单词及其计数
完整代码示例
1. 输入读取线程(负责捕获空格触发的单词)
import java.io.IOException; import java.util.concurrent.ConcurrentHashMap; public class InputReaderThread extends Thread { private final ConcurrentHashMap<String, Integer> wordCounts; // 传入共享的线程安全计数集合 public InputReaderThread(ConcurrentHashMap<String, Integer> wordCounts) { this.wordCounts = wordCounts; } @Override public void run() { StringBuilder currentWord = new StringBuilder(); try { int charCode; // 循环读取每个字符,直到输入结束(Ctrl+C) while ((charCode = System.in.read()) != -1) { char inputChar = (char) charCode; // 遇到空格或回车时,提交当前单词 if (inputChar == ' ' || inputChar == '\n') { if (currentWord.length() > 0) { String word = currentWord.toString().trim(); // 线程安全地更新单词计数:不存在则设为1,存在则加1 wordCounts.put(word, wordCounts.getOrDefault(word, 0) + 1); currentWord.setLength(0); // 重置临时字符串,准备下一个单词 } // 按下回车时结束输入(可根据需求调整退出逻辑) if (inputChar == '\n') { System.out.println("\n输入已结束,程序将在3秒后退出..."); Thread.sleep(3000); break; } } else { // 非分隔符字符,拼接进当前单词 currentWord.append(inputChar); } } } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
2. 计数显示线程(负责实时展示单词统计)
import java.util.concurrent.ConcurrentHashMap; public class WordCountDisplayThread extends Thread { private final ConcurrentHashMap<String, Integer> wordCounts; private volatile boolean isRunning = true; // 线程终止标记 public WordCountDisplayThread(ConcurrentHashMap<String, Integer> wordCounts) { this.wordCounts = wordCounts; } @Override public void run() { while (isRunning) { try { // 每秒刷新一次显示内容 Thread.sleep(1000); System.out.print("\r当前单词统计:"); // 用\r覆盖上一行输出,避免刷屏 wordCounts.forEach((word, count) -> System.out.printf("%s:%d ", word, count)); } catch (InterruptedException e) { Thread.currentThread().interrupt(); isRunning = false; } } } // 提供外部终止线程的方法 public void stopDisplay() { isRunning = false; } }
3. 主程序(启动两个线程)
import java.util.concurrent.ConcurrentHashMap; public class WordCounterApp { public static void main(String[] args) { // 用ConcurrentHashMap保证多线程下的读写安全 ConcurrentHashMap<String, Integer> wordCounts = new ConcurrentHashMap<>(); InputReaderThread readerThread = new InputReaderThread(wordCounts); WordCountDisplayThread displayThread = new WordCountDisplayThread(wordCounts); // 启动线程 readerThread.start(); displayThread.start(); try { // 等待输入线程结束,再终止显示线程 readerThread.join(); displayThread.stopDisplay(); displayThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } }
关键注意事项
- 线程安全:必须使用
ConcurrentHashMap这类线程安全的容器,避免多线程读写时出现数据混乱 - 输入扩展:如果需要支持制表符、换行符等其他分隔符,可以把判断条件改成
Character.isWhitespace(inputChar) - 大小写处理:如果需要忽略大小写统计(比如
Hello和hello算同一个单词),可以在提交时转成小写:word.toLowerCase() - 退出逻辑:示例中用回车结束输入,你也可以改成按特定字符(比如
q)触发退出
内容的提问来源于stack exchange,提问作者user3578760
相关产品推荐
相关产品推荐

