当前位置: 首页 > 知识库问答 >
问题:

为什么多个nextInt()可以工作?

鲁熙云
2023-03-14

在以下Java代码中

Scanner input = new Scanner(System.in);    //Cmd1
int i1,i2;                                 //Cmd2
i1 = input.nextInt();                      //Cmd3
System.out.println("value of i1 is "+ i1); //Cmd4
i2 = input.nextInt();                      //Cmd5
System.out.println("value of i2 is "+ i2); //Cmd6
String s1;                                 //Cmd7
input.nextLine();                          //Cmd8
s1 = input.nextLine();                     //Cmd9
System.out.println("value of s1 is "+ s1); //Cmd10

我在控制台中得到以下输出

<myinput> 1
<output>  value of i1 is 1
<myinput> 2
<output>  value of i2 is 2
<myinput> firstString
<output>  value of s1 is firstString

在使用next()或nextFoo()后,从扫描仪查看答案时跳过nextLine()?,我们必须添加Cmd8的原因是,nextInt()一直读取输入,直到将输入发送到程序,并将输入放回输入流的前面。现在,当“Cmd8”中的nextLine()开始读取它时,它会在输入流的开始处发现前面没有任何字符串,它假定用户没有输入任何内容,因此将空字符串作为输入并转到Cmd9

我的疑问是,nextInt()也会一直读到\n(根据我的经验,这意味着Cmd3一直在等待,直到我按下enter键为止)为什么Cmd5一直在等待我的输入。它还应该在输入流的开头找到,并假设我没有输入任何内容,并将空整数作为输入(类似于Cmd8的行为)。这里发生了什么?


共有2个答案

姜建德
2023-03-14
匿名用户

请注意以下摘录自Scanner#next文档:

从此扫描仪中查找并返回下一个完整的令牌。完整标记的前面和后面都是与分隔符模式匹配的输入。

扫描器使用的默认分隔符是\p{javaWhitespace},如下所示:

import java.util.Scanner;

public class Main {
    public static void main(String... args) {
        Scanner input = new Scanner(System.in);
        System.out.println(input.delimiter());
    }
}

以下几行代码显示了在找到10或hello时如何找到完整的令牌,即无论您按多少次Enter键,都会继续请求输入,直到输入非空白字符。注意:如果是nextInt(),则值10可解析为int,但不是hello,因此将引发输入不匹配异常。

public class Main {
    public static void main(String... args) {
        System.out.println(Character.isWhitespace('\n'));
        System.out.println("\n\n\n\n\n".split("\\p{javaWhitespace}+").length);
        System.out.println("10\n".split("\\p{javaWhitespace}+").length);
        System.out.println("hello\n".split("\\p{javaWhitespace}+").length);
    }
}

输出:

true
0
1
1

这适用于所有的nextXXX(),除了nextLine(),其文档(以下摘录)非常清楚它与其他nextXXX()的不同之处。

使此扫描仪超过当前行并返回跳过的输入。此方法返回当前行的其余部分,不包括末尾的任何行分隔符。该位置设置为下一行的开头。由于此方法继续在输入中搜索行分隔符,因此如果不存在行分隔符,它可能会缓冲所有要跳过的行的输入搜索。

换句话说,nextLine()将捕获所有内容,包括直接输入或从上一个输入中剩余的空格字符。

慕嘉茂
2023-03-14

我已经通过调试JRE Scanner类方法分析了您的问题。当您调用nextInt函数时,Scanner看起来是当前缓冲区。如果没有可用的输入,开始监听键盘,直到您按下Enter键,整个键盘字符附加到缓冲区并尝试匹配它是否是整数。当找到一个整数nextInt返回值并增加缓冲区的位置索引。下一步,您再次调用nextInt,只有\n字符,然后将其丢弃并等待下一个整数模式。此外,缓冲区的下一个字符又是\n。当您调用nextLine时,它会查看缓冲区并打印一个空行。因此第二个nextLine以空文本开头。

也许这会让人困惑。让我们看看场景:

注:索引表示缓冲区的读取位置。

  1. 步骤
i1 = input.nextInt();
keyboard = 1 2 {Enter}
buffer = | 1 | 2 | \n |
index  =   ^

返回12,下一个缓冲区位置位于\n

java prettyprint-override">i2 = input.nextInt();
keyboard = 3 4 {Enter}
buffer = | 1 | 2 | \n | 3 | 4 | \n |
index  =           ^

返回34,下一个缓冲区位置位于第二个\n

input.nextLine();

缓冲区具有\n字符,因此Scanner不等待键盘并返回值。

buffer = | 1 | 2 | \n | 3 | 4 | \n |
index  =                         ^

返回空文本

s1 = input.nextLine();
keyboard = test {Enter}
buffer = | 1 | 2 | \n | 3 | 4 | \n | t | e | s | t | \n |
index  =                             ^

返回测试

 类似资料:
  • 使用 ubuntu22.04 发现使用 sudo apt update && sudo apt upgrade -y 更新软件包的时候,也会更新 Kernel 机器上有好多个 Kernel 了,ubuntu 给我下载这么多 Kernel 干嘛呢?

  • 我在vue3项目中使用了 '@vueuse/gesture' 的useWheel函数来帮助监听滚轮在一个元素上的滑动,但我发现指令能生效,而Composable的写法却不生效,无法触发wheelHandler回调。 我在调用useWheel之前也log了 workspaceArea.value是有值的,正常的。 是我的代码写的有问题吗?还是库的bug?

  • 问题内容: 我正在尝试向div添加ajax响应(它是带有表,表单等的HTML代码)。 在FF中工作完美,但在IE中却给了我一个未知的错误。 我尝试了很多东西,但是只有当我添加jQuery并在要插入代码的div上运行该方法时,它才起作用。 有人在乎解释为什么这样做有效,而不是简单吗?我尝试查看代码,但我想我不是JS的佼佼者,因为我不了解它在做什么。 问题答案: IE 有 多个 文档(pre | ta

  • 所以我有一个OpenGL程序,可以分割屏幕。经过研究,我的代码如下所示: 然而,我不明白它为什么会工作,我肯定错过了OpenGL的一些基本功能。我不明白的部分是在每个“屏幕”的末尾,我画了一个带纹理的四边形(最后5行代码)。但是这种纹理是从哪里来的呢?为什么它恰好是我为屏幕绘制的场景的纹理?我从来没有做过glBindTexture或glEnable(GL_TEXTURE_2D)任何事情,事实上,在

  • 我执行以下代码,没有错误,在输出中我看到了消息。你能解释一下这种奇怪的行为吗? 你可以查看在线演示

  • 问题内容: 假设我们的应用程序只有一个线程。然后我们正在使用,这是什么问题? 我的意思是,如果可以通过同步处理多个线程,那么使用单线程有什么问题? 为什么要改用? 问题答案: 是线程安全的,这意味着它们具有同步的方法来控制访问,因此一次只有一个线程可以访问StringBuffer对象的同步代码。因此,在多个线程可能试图同时访问同一StringBuffer对象的多线程环境中,StringBuffer