
system.in.read()在处理用户输入时,除了读取用户键入的字符外,还会读取回车符和换行符,导致循环或条件判断意外执行多次。本文将深入分析这一现象的成因,并提供一种健壮的方法来正确处理低级别字符输入,确保程序按预期逻辑运行。
在J*a中,System.in.read()是一个低级别的输入方法,用于从标准输入流中读取单个字节的数据。它返回读取到的字节的整数表示(0-255),如果到达流的末尾则返回-1。当我们需要在循环中根据用户输入的单个字符来控制程序流程时,可能会遇到一些意想不到的行为。
考虑以下代码示例,它尝试在用户输入非'S'字符时持续循环:
import j*a.io.IOException;
public class ForTest {
public static void main(String[] args)
throws j*a.io.IOException {
int i;
System.out.println("Press S to stop.");
for(i = 0; (char) System.in.read() != 'S'; i++)
System.out.println("Pass #" + i);
}
}当运行这段代码并输入一个字符(例如'a')后按下回车键,预期是循环体执行一次,然后等待下一次输入。然而,实际输出却显示循环体执行了三次:
a Pass #0 Pass #1 Pass #2 w Pass #3 Pass #4 Pass #5 1 Pass #6 Pass #7 Pass #8 2 Pass #9 Pass #10 Pass #11
这种现象表明,每次用户输入一个字符并按下回车键,System.in.read()似乎被调用了三次,导致循环体意外地执行了多次。
这种“三次输出”的根源在于操作系统和J*a对键盘输入以及行结束符的处理方式。当用户在命令行界面输入一个字符(例如'a')并按下Enter键时,System.in实际上接收到的不仅仅是字符'a',还包括了行结束符。
在大多数操作系统中,按下Enter键会产生以下一个或两个控制字符:
具体来说:
由于System.in.read()每次调用都会从输入缓冲区中读取并返回一个字节,因此,当用户输入'a'并按下Enter(在Windows上产生\r\n)时,输入缓冲区中会依次包含'a'、\r和\n这三个字符。
回到我们的for循环条件:(char) System.in.read() != 'S'。
这就是为什么每次输入一个字符并按Enter键,循环体会执行三次的原因。
要解决这个问题,关键在于在读取用户实际输入的字符后,需要额外地清空输入缓冲区中剩余的回车符和换行符,以避免它们影响后续的read()调用。
Glarity
Glarity是一款免费开源的AI浏览器扩展,提供YouTube视频总结、网页摘要、写作工具等功能,支持免费的镜像翻译,电子邮件写作辅助,AI问答等功能。
131
查看详情
我们可以通过在读取到有效字符后,继续读取并丢弃所有直到遇到换行符(\n)的字符来实现这一点。这样可以兼容处理不同操作系统上的行结束符差异。
以下是改进后的代码示例:
import j*a.io.IOException;
public class CorrectInputHandler {
public static void main(String[] args) throws IOException {
int i = 0;
char inputChar;
System.out.println("Press S to stop.");
// 使用while(true)循环,并在内部处理输入和退出逻辑,
// 这样可以更好地控制输入流的清理。
while (true) {
System.out.print("Pass #" + i + ". Please enter a character: ");
inputChar = (char) System.in.read(); // 读取用户输入的实际字符
// 关键步骤:清空输入缓冲区中剩余的字符,直到遇到换行符
// 这会消耗掉 \r (如果存在) 和 \n
int nextChar;
while ((nextChar = System.in.read()) != -1 && nextChar != '\n') {
// 循环体为空,仅用于消耗字符
}
// 判断用户输入是否为停止字符
if (inputChar == 'S' || inputChar == 's') { // 允许大小写's'停止
System.out.println("Stopping loop as 'S' was entered.");
break; // 退出循环
}
System.out.println("Loop continues.&q
uot;);
i++;
}
System.out.println("Loop finished.");
}
}运行上述改进后的代码,每次输入一个字符并按下Enter键后,循环体将只执行一次,符合预期行为。
平台差异兼容性: 上述解决方案中通过循环读取直到\n的方式,能够很好地兼容Windows(\r\n)和Unix/Linux/macOS(\n)的行结束符差异。它会先消耗\r(如果存在),然后消耗\n,确保缓冲区被正确清空。
更高级的输入方式: 对于大多数实际应用场景,推荐使用j*a.util.Scanner类来处理用户输入,而不是直接使用System.in.read()。Scanner提供了更高级、更方便的方法,如nextLine()(读取一整行并自动处理行结束符)或next()(读取下一个令牌),它内部已经处理了这些低级别的字符流细节,使得输入操作更加健壮和易用。
import j*a.util.Scanner;
public class ScannerInputExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int i = 0;
System.out.println("Press S to stop.");
while (true) {
System.out.print("Pass #" + i + ". Please enter a character: ");
String inputLine = scanner.nextLine(); // 读取整行输入
if (inputLine.isEmpty()) { // 处理空行输入
System.out.println("Empty input, please try again.");
continue;
}
char inputChar = inputLine.charAt(0); // 取第一个字符进行判断
if (inputChar == 'S' || inputChar == 's') {
System.out.println("Stopping loop as 'S' was entered.");
break;
}
System.out.println("Loop continues.");
i++;
}
scanner.close(); // 关闭Scanner
System.out.println("Loop finished.");
}
}异常处理: System.in.read()方法会抛出j*a.io.IOException,因此在使用时必须捕获或在方法签名中声明抛出。
输入缓冲: System.in通常是缓冲的,这意味着你键入的字符可能不会立即发送给程序,而是先存储在一个缓冲区中,直到你按下Enter键,整个输入行才会被发送。这是System.in.read()会一次性读取到\r和\n的原因。
System.in.read()是一个处理低级别字符输入的强大工具,但它要求开发者对输入流的工作原理有深入理解。当用户通过键盘输入时,按下Enter键会产生额外的回车符和换行符,这些字符也会被System.in.read()读取,从而可能导致程序逻辑出现意外。
为了确保程序按预期运行,特别是在需要精确控制每次字符输入时,务必在读取有效字符后,手动清空输入缓冲区中剩余的行结束符。然而,在大多数日常开发中,推荐使用j*a.util.Scanner等更高级的输入工具,它们提供了更抽象、更易于使用的接口,能够自动处理这些低级别的输入细节,提高代码的健壮性和可读性。理解System.in.read()的底层机制,有助于我们更好地掌握J*a的I/O操作,并在需要时进行精细控制。
以上就是J*a System.in.read()行为解析:处理用户输入中的回车符的详细内容,更多请关注其它相关文章!
相关文章:
J*aScript map 迭代中检测空数组元素的有效方法
如何使用Node.js csv 包按条件移除含空字段的CSV记录
sublime如何只显示或隐藏特定类型文件_sublime侧边栏文件过滤
漫蛙漫画网页端入口 漫蛙2官方正版漫画站点
J*aScript中在Map循环中检测并处理空数组元素
深入理解J*a合成构造器:何时以及为何阻止其生成
Go Martini框架:动态服务解码后的图片内容
Golang如何通过reflect获取匿名字段方法_Golang reflect匿名字段方法访问技巧
J*aScript井字棋(Tic-Tac-Toe)核心交互逻辑实现教程
PDF文件体积过大处理_PDF压缩技巧详解
php源码怎么在电脑上测试_电脑测试php源码方法步骤【教程】
在WordPress中通过REST API访问受BasicAuth保护的站点内容
Surface怎么安装系统 微软Surface Pro U盘重装win11教程
PHP中获取MongoDB服务器运行时间(Uptime)的专业指南
电脑屏幕颜色不舒服怎么办_Windows夜间模式与色彩校准教程【护眼技巧】
现代化 SciPy 一维插值:interp1d 的替代方案与最佳实践
Go调试环境为何无法启动_Go调试器启动失败原因与解决策略
谷歌google账号注册详细步骤 谷歌账号注册官方教程
c++如何使用Meson构建系统_c++比CMake更快的构建工具
Python多线程中正确使用sigwait处理SIGALRM信号
汽水音乐在线解析 汽水音乐在线解析入口
Win10系统服务哪些可以禁用 Win10安全优化服务列表【干货】
win11跳过OOBE三种方法 Win11跳过OOBE设置步骤
Promise错误处理:在catch后终止链式then执行的策略
聚水潭ERP登录页面入口 聚水潭ERP官网登录界面
QQ邮箱官方网页版登录 QQ邮箱个人邮箱快速访问
Golang如何使用const iota_Go iota常量计数器讲解
Lar*el Form Request 中唯一性验证更新操作的正确实践
zookeeper 都有哪些功能?
Excel中VLOOKUP的第四个参数是干什么用的_Excel VLOOKUP第四参数作用解析
c++20的std::jthread是什么_c++可中断线程与RAII式管理
网易大神怎么保存别人动态的图片_网易大神动态图片保存方法
12306选座怎么选到特殊座位_12306特殊座位选择注意事项
Lar*el Form Request中唯一性验证在更新操作中的正确实现
qq邮箱日历功能怎么用_创建日程与会议邀请的技巧
利用5118提升短视频内容效果_5118短视频关键词优化方法
Python异步编程实践:使用Binance API构建实时交易数据流
163邮箱注册官网 免费申请163个人邮箱
MongoDB聚合管道:正确匹配对象数组中_id的方法
Win10文件资源管理器“此电脑”分组怎么关 Win10恢复经典视图【技巧】
MAC如何安全彻底地删除文件_MAC使用终端命令确保文件无法被恢复
必由学在线入口 必由学网页版快速登录入口
Lar*el 递归关系中排除指定分支的教程
QQ邮箱官网登录入口 QQ邮箱网页版邮箱快速登录
C++如何比较两个字符串_C++ string compare函数与操作符对比
大象笔记网页版入口 印象笔记网页版登录入口
J*aScript数组对象转换:按指定键分组与值收集
基于动态规划的房屋花卉种植最小成本算法详解
win11开机启动修复循环怎么办 Win11无法进入系统高级启动解决方法【修复】
百度网盘网页版入口 百度网盘网页版官方登录网址