小心Java中的扫描器方法

对于新生来说,使用Java的Scanner编写交互式程序通常很有趣。 不幸的是,有一些令人讨厌的陷阱并不能真正为这些学生带来积极的体验。 因此,我收到一个警告:请谨慎使用Java中的Scanner方法。

The Problem Students Encounter

第一次学习Java时,我从未使用过Scanner。 实际上,直到有两年的行业经验我才接触过该实用程序。 但是无论出于何种原因,我目前所在机构的Java课程都广泛使用Scanner,因此我想谈一谈Scanner的某些方法的陷阱。

特别是,我想谈谈使用扫描仪从命令行读取用户输入的情况。 通常,这是可取的,因为我们想提示用户一些输入,例如他们的姓名或喜欢的号码。 然后,我们进行一些有趣的计算,并将结果转储给用户。 我举一个例子(用户输入为粗体):

输入你的名字:杰里米 Hi, 杰里米!

在此示例中,我们已提示用户输入其名称,然后将其吐回给他们。 我们可以使用以下Java代码片段来实现此目的:

Scanner input = new Scanner(System.in);
System.out.print("Enter your name: ");
String name = input.nextLine();
System.out.println("Hi, " + name + "!");

还算不错! 但是,如果我们要一个数字怎么办? 对我们来说幸运的是,扫描器API拥有大量的令牌生成器方法,例如nextLine()从用户那里获取我们想要的任何东西,并自动将其转换为适当的类型。 也就是说,使用它们时要小心。

The Explanation Students Desire

此时,很多学生会问我:

有什么大不了的? 我为什么要打电话nextLine()可以直接调用适当的方法时手动解析值?各地学生

而且,他们的担心是完全正确的! 我绝不会要求任何人做比自己更多的工作,那有什么大不了的?

Problems

好吧,事实证明,如果您开始使用类似nextLine()如果没有真正注意解析的内容,就会遇到一些问题。

也许最明显的问题是打字问题。 例如,假设我们要求用户输入数字,然后他们给我们起了名字。 没有正确的错误处理,我们的解决方案肯定会崩溃。 也就是说,这种问题并不难发现或解决。 毕竟,一旦用户输入无效的文本,解决方案就会崩溃并显示一个有用的错误。

取而代之的是,存在一个更为邪恶的问题,即使是经验丰富的程序员也同意很难解决,并且在我们开始混合使用各种Scanner方法时就会浮出水面。 请看下面的示例,看看如果我们为程序提供数字25和我的名字,您是否可以找出结果。

Scanner input = new Scanner(System.in);
System.out.print("Enter your age: ");
int age = input.nextInt();
System.out.print("Enter your name: ");
String name = input.nextLine();
System.out.println("Your name is " + name + " and you are " + age);

无需过多研究解决方案,普通人会说此解决方案会显示“您的名字叫Jeremy,而您25岁”。 而且,老实说,我一点也不责怪他们。 逻辑是存在的,但结果却没有。 幸运的是,我不会让你吊死的!

Bug Hunting

If you’ve jumped ahead already and tested this solution yourself, you’ll have noticed that something strange happens. For starters, our output is wrong. Instead of “Your name is Jeremy and you are 25”, the output will read “Your name is and you are 25”. Right away, we’ll notice that the name is missing from the output meaning that the name variable is probably storing an empty String.

更糟糕的是,当我们实际运行该解决方案时,我们会看到我们仅被提示输入一次。 输入年龄后,整个脚本将按以下方式转储到屏幕上(用户输入为粗体):

输入您的年龄:25 Enter your name: Your name is and you are 25

在这一点上,我们将不知所措,想知道如何致电nextLine()刚刚立即返回了一个空字符串。 幸运的是,我有答案!

Escape Sequences

每当我们提示用户进行输入时,他们都会得到一条花哨的行,可以在其中转储一些文本并点击进入。 请留意最后一部分,因为它至关重要。

That text is composed of characters which all have an underlying numeric value. For instance, the letter ‘a’ has the numeric value 97 while the number ‘7’ has the numeric value 55—oddly enough. Luckily, there’s no need to memorize all these values. Instead, check out an ASCII table for a list of the first 256 characters.

如果浏览该表格,我们会注意到其中有一些字符有些奇怪。 例如,该表的整个第一列包含转义序列的列表。 这些字符具有特殊目的,但在屏幕上并不总是清晰可见。

事实证明,其中一些转义序列可用来表示文本中的行尾:10(换行)和13(回车)。 根据系统的不同,这两个转义序列的任何组合都可以用于标记行尾。

Rogue New Lines

为了便于讨论,我们假设系统使用换行符标记换行符。 在Java中,换行符可以使用'\ n'编写。 换句话说,每次我们按下回车键时,我们都可以想象这些字符之一潜入文本中。

现在我们已经知道了转义序列,为什么我们不再寻找漏洞了呢? 注意我们声明年龄变量的那一行。 这就是错误开始显现的地方。

Scanner input = new Scanner(System.in);
System.out.print("Enter your age: ");
int age = input.nextInt();
System.out.print("Enter your name: ");
String name = input.nextLine();
System.out.println("Your name is " + name + " and you are " + age);

您知道错误可能在哪里吗? 我会给你一个提示。 的nextInt()方法只关心获取下一个数字。 换句话说,它会留下我们流氓换行符('\ n')。

打电话之后nextInt(),我们提示用户输入他们的姓名。 那时,我们致电nextLine()直到下一个新行字符为止。 不幸的是,我们打来的时候留下了一个nextInt()。 结果是,nextLine()不必等到我们输入任何文本。 它只是返回一个空字符串。

如果不清楚,我建议尝试在以空格分隔的年龄列表上方输入该代码段。 例如,签出以下记录(用户输入为粗体):

输入您的年龄:20 19 31 15 Enter your name: Your name is 19 31 15 and you are 20

如我们所见,年龄被设置为列表中的第一个数字(在本例中为“ 20”),程序从不提示输入名称。 取而代之的是,将输入缓冲区的其余部分(在这种情况下为“ 19 31 15 \ n”)读入一行并保存为名称。

在下一节中,我们将讨论如何处理遗留的换行符。

Patch Job

幸运的是,有几个针对此问题的修复程序。 一个依赖于捕获我们的错误,另一个依赖于解决问题的根本原因。

既然我们知道已经离开了一条新线,那么我们要做的就是消耗掉它。 换句话说,我们可以打电话给nextLine()在像平常一样调用它之前:

Scanner input = new Scanner(System.in);
System.out.print("Enter your age: ");
int age = input.nextInt();
System.out.print("Enter your name: ");
input.nextLine();
String name = input.nextLine();
System.out.println("Your name is " + name + " and you are " + age);

请注意,我们如何添加了对nextLine()就在我们存储名称的位置上方。 现在,当我们留下那个“ \ n”字符时,我们将在第5行中清理混乱。然后,在第6行中我们可以继续生活。

或者,我们可以通过替换我们的问题来完全消除此问题nextInt()打电话给nextLine()。 然后,我们需要解析String以获取所需的整数:

Scanner input = new Scanner(System.in);
System.out.print("Enter your age: ");
int age = Integer.parseInt(input.nextLine());
System.out.print("Enter your name: ");
String name = input.nextLine();
System.out.println("Your name is " + name + " and you are " + age);

无需费心清理自己,我们可以一次性使用整行并手动解析它。 就个人而言,我更喜欢此选项,但两者都可以正常工作。 无论哪种情况,我们都已完全消除了此令人讨厌的Scanner错误。

Open Forum

因此,使用Scanner API时要谨慎讲故事。 尽管有许多方法可为您提供方便,但将它们混合使用会导致某些难以跟踪的讨厌的错误。 当然,这取决于您决定如何使用新知识。

无论如何,仅此而已! 如果您喜欢本文或有任何反馈,请在评论中告诉我。 此外,如果您有使用Java处理Scanner的技巧或窍门,请随时分享。

And if you're feeling particularly generous, subscribe to my website, The Renegade Coder.

from: https://dev.to//renegadecoder94/be-careful-with-scanner-methods-in-java-460m

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值