风之语录 發表於 2025-8-10 13:09:00

从底层逻辑,谈谈next()和nextLine()配合使用时,出现的“跳过输入”的现象

<details>
<summary>点击查看代码</summary>
<pre><code>package com.jia.scanner;

import java.util.Scanner;

public class Demo01 {
    public static void main(String[] args) {
      //创建一个扫描器对象,用于接受键盘数据
      Scanner sc = new Scanner(System.in);
      System.out.println("使用next方式接受:");
      //判断用户有没有输入字符串
      if (sc.hasNext()){
            //使用next方式接受
            String str = sc.next();
            System.out.println("输出的内容:" + str);
      }

      System.out.println("============================================");

      System.out.println("使用nextLine:");
      if (sc.hasNextLine()){
            String str = sc.nextLine();
            System.out.println("输出的内容:" + str);
      }
      //凡是属于IO流的类,如果不关闭会一直占用资源,要养成习惯用完就关掉
      sc.close();//为了节省资源
    }
}

</code></pre>
</details>
<p><strong>这段代码,运行后输出的结果是:</strong><br>
<img src="https://img2024.cnblogs.com/blog/3670253/202508/3670253-20250810122519290-867731019.png"><br>
会出现<strong>跳过用户输入的现象</strong>。但是,并不符合我的需求,我希望是在使用nextLine前,可以再次从键盘输入新的内容,再输出新的结果。<br>
接下来,我们可以从输入缓冲区机制和next还有nextLine两种方法的底层处理逻辑进行分析,该现象产生的原因:</p>
<ol>
<li>数据是在<strong>输入缓冲区</strong>作为“中间站”暂存<br>
计算机在处理键盘输入时,并不是让程序直接“实时”的读取每一个按键,这样效率太低了,而是通过<strong>输入缓冲区</strong>作为中间层:
<ul>
<li>用户敲击键盘的字符会先存入缓冲区,直到用户按下回车键(\n),缓冲区才会通知程序“有数据可以读取”</li>
<li>程序中的Scanner类本质就是从缓冲区中读取数据,而不是直接从键盘读取</li>
</ul>
</li>
<li>next()方法的底层处理逻辑:<br>
next()的核心逻辑是<strong>以空白字符为分隔符的非空白字符串读取</strong>,具体步骤是:
<ul>
<li><strong>跳过前导空白字符</strong>:自动忽略缓冲区中开头的所有空白字符(空格、指标符\t、换行符\n等)。</li>
<li><strong>读取有效的字符</strong>:从第一个非空白字符开始读取,持续读取直到遇到<strong>下一个空白字符</strong>(空格、换行等)。</li>
<li><strong>终止但是不消耗分隔符</strong>:当遇到空白字符时,next()会停止读取数据,但是<strong>这个空白字符不会被从缓冲区中移除</strong>,仍然留在缓冲区中。</li>
</ul>
</li>
<li>nextLine()方法的底层处理逻辑:<br>
nextLine()的核心逻辑是<strong>读取一整行内容,知道换行符为止</strong>,具体步骤是:
<ul>
<li><strong>从当前位置开始读取数据</strong>:不跳过任何字符,直接从缓冲区当前位置开始读取数据。</li>
<li><strong>以换行符为终止符</strong>:持续读取所有字符(包括空白字符),直到遇到\n(换行符)。</li>
<li><strong>消耗终止符</strong>:读取完成后,会将终止的\n(换行符)从缓冲区中移除(即“消耗”掉)。<br>
<strong>举例:</strong><br>
用户输入“hello world\n”(\n是用户按回车键产生的换行符),计算机缓冲区的内容为“hello world\n”。<br>
next()执行后:</li>
</ul>
</li>
</ol>
<ul>
<li>读取到“hello”(非空白字符开始,知道空格停止);</li>
<li>缓冲区中剩余“ world\n”(空格和后续字符未被消耗移除);<br>
nextLine()执行后:</li>
<li>读取到“ world”(从当前位置,即空格开始,知道\n换行符为止);</li>
<li>同时消耗掉\n(换行符),缓冲区变为空。<br>
<strong>综上所述,出现跳过输入现象的根本原因是:</strong></li>
</ul>
<ol>
<li>next()读取后,缓冲区中残留了未被消耗掉的空白字符(如空格)和换行符前的字符内容;</li>
<li>后续的nextLine()读取时,会直接从缓冲区这些残留的内容(从空白字符到\n),并消耗掉\n(换行符);</li>
<li>由于执行完next()读取都,缓冲区还有内容(从空白字符到\n)未被消耗,所以,nextLine()无需等待用户输入新内容,导致,看起来出现了“跳过输入现象”。<br>
当然,存在解决方法,只需在next()后额外调用一次nextLine()清空缓冲区,即可。<br>
<strong>本质是:</strong><br>
让第一次nextLine()消耗掉next()残留的空白字符和\n,使缓冲区为空。这样,后续真正需要使用nextLine()就会等待用户输入新内容(因为缓冲区已经被清空,必须等待新的\n触发)。</li>
</ol>
<details>
<summary>点击查看代码</summary>
<pre><code>package com.jia.scanner;

import java.util.Scanner;

public class Demo01 {
    public static void main(String[] args) {
      //创建一个扫描器对象,用于接受键盘数据
      Scanner sc = new Scanner(System.in);
      System.out.println("使用next方式接受:");
      //判断用户有没有输入字符串
      if (sc.hasNext()){
            //使用next方式接受
            String str = sc.next();
            sc.nextLine();//紧跟着,使用nextLine释放空格,程序才会接着让用户输入
            System.out.println("输出的内容:" + str);
      }

      System.out.println("============================================");

      System.out.println("使用nextLine:");
      if (sc.hasNextLine()){
            String str = sc.nextLine();
            System.out.println("输出的内容:" + str);
      }
      //凡是属于IO流的类,如果不关闭会一直占用资源,要养成习惯用完就关掉
      sc.close();//为了节省资源
    }
}
</code></pre>
</details>
该代码运行结果如下:
<p><img src="https://img2024.cnblogs.com/blog/3670253/202508/3670253-20250810130150527-1281390301.png"></p>
<p>符合我的需求!</p><br><br>
来源:https://www.cnblogs.com/weijia-2/p/19030608
頁: [1]
查看完整版本: 从底层逻辑,谈谈next()和nextLine()配合使用时,出现的“跳过输入”的现象