使用next()或nextFoo()后,Scanner正在跳过nextLine()?

我正在使用Scanner方法nextInt()nextLine()来读取输入。

它看起来像这样:

 System.out.println("Enter numerical value"); int option; option = input.nextInt(); // Read numerical value from input System.out.println("Enter 1st string"); String string1 = input.nextLine(); // Read 1st string (this is skipped) System.out.println("Enter 2nd string"); String string2 = input.nextLine(); // Read 2nd string (this appears right after reading numerical value) 

问题是在输入数值后,跳过第一个input.nextLine()并执行第二个input.nextLine() ,这样我的输出如下所示:

 Enter numerical value 3 // This is my input Enter 1st string // The program is supposed to stop here and wait for my input, but is skipped Enter 2nd string // ...and this line is executed and waits for my input 

我测试了我的应用程序,看起来问题在于使用input.nextInt() 。 如果我删除它,那么string1 = input.nextLine()string2 = input.nextLine()都按我希望的那样执行。

这是因为Scanner.nextInt方法不消耗输入的最后一个换行符 ,因此在下次调用Scanner.nextLine会消耗该换行符

Scanner.next()或任何Scanner.nextFoo方法( nextLine本身除外Scanner.next()之后使用Scanner.nextLine时,您将遇到类似的行为。

解决方法:

  • Scanner.nextIntScanner.nextFoo之后触发一个空白的Scanner.nextLine调用以消耗该行的其余部分,包括换行符

     int option = input.nextInt(); input.nextLine(); // Consume newline left-over String str1 = input.nextLine(); 
  • 或者,如果您通过Scanner.nextLine读取输入并将输入转换为您需要的正确格式,那将更好。 例如,使用Integer.parseInt(String)方法的整数。

     int option = 0; try { option = Integer.parseInt(input.nextLine()); } catch (NumberFormatException e) { e.printStackTrace(); } String str1 = input.nextLine(); 

问题在于input.nextInt()方法 – 它只读取int值。 因此,当您继续使用input.nextLine()读取时,您会收到“\ n”Enter键。 所以要跳过这个,你必须添加input.nextLine() 。 希望现在应该清楚这一点。

试试吧:

 System.out.print("Insert a number: "); int number = input.nextInt(); input.nextLine(); // This line you have to add (It consumes the \n character) System.out.print("Text1: "); String text1 = input.nextLine(); System.out.print("Text2: "); String text2 = input.nextLine(); 

这是因为当你输入一个数字然后按Enter键时input.nextInt()只消耗数字,而不是“行尾”。 当input.nextLine()执行时,它会消耗第一个输入中仍在缓冲区中的“行尾”。

相反,在input.nextInt()之后立即使用input.nextInt()

java.util.Scanner似乎有很多关于这个问题的问题。 我认为更可读/惯用的解决方案是在调用nextInt()之后调用nextInt() scanner.skip("[\r\n]+")来删除任何换行符。

编辑:正如下面提到的@PatrickParker,如果用户在数字后输入任何空格,这将导致无限循环。 有关与skip一起使用的更好模式,请参阅他们的答案: https : //stackoverflow.com/a/42471816/143585

它是因为input.nextInt(); 不捕获换行符。 你可以像添加一个input.nextLine(); 下。
或者,您可以使用C#样式并将nextLine解析为整数,如下所示:

 int number = Integer.parseInt(input.nextLine()); 

这样做也很有效,它为您节省了一行代码。

你需要知道的事情:

  • 表示几行的文本也包含行之间的不可打印字符(我们称之为行分隔符)

    • 回车(CR – 用字符串文字表示为"\r"
    • 换行(LF – 在字符串文字中表示为"\n"
  • 当你从控制台读取数据时,它允许用户输入他的回复,当他完成时,他需要以某种方式确认这一事实。 为此,用户需要按键盘上的“输入”/“返回”键。

    重要的是,除了确保将用户数据放置到标准输入 (由Scanner读取的System.in表示)之外,此键还会发送OS依赖的行分隔符(例如Windows \r\n )。

    因此,当您向用户询问age等值以及用户类型42并按Enter键时,标准输入将包含"42\r\n"

问题

Scanner#nextInt (和其他Scanner#next Type Scanner#nextInt Scanner#next Type方法)不允许扫描仪使用这些行分隔符。 它将从System.in读取它们(扫描器如何知道用户没有更多的数字表示age值而不是面对空格?),这将从标准输入中删除它们,但它也会在内部缓存这些行分隔符 。 我们需要记住的是,所有Scanner方法始终都是从缓存的文本开始扫描的。

现在Scanner#nextLine()只收集并返回所有字符, 直到找到行分隔符 (或流结束)。 但是,由于在扫描程序的缓存中立即找到从控制台读取数字后的行分隔符,它会返回空字符串,这意味着扫描程序无法在这些行分隔符(或流结束)之前找到任何字符。
BTW nextLine消耗那些行分隔符。

因此,当你想要求数字然后是整行时,同时避免作为nextLine结果的空字符串

  • 消耗来自Scanners缓存的nextInt留下的行分隔符
    • 调用nextLine
    • 或者通过调用skip("\\R")让扫描程序跳过与\R匹配的部分,代表行分隔符(有关\R : https : //stackoverflow.com/a/31060125的更多信息)
  • 不要使用nextInt (也不是next或任何nextTYPE方法)。 而是使用nextLine读取整个数据,并将每行中的数字(假设一行只包含一个数字)解析为正确的类型,如int via Integer.parseInt

BTWScanner#next Type方法可以跳过分隔符(默认情况下所有空格,如制表符,行分隔符),包括扫描程序缓存的那些空格,直到它们找到下一个非分隔符值(标记)。 感谢您输入"42\r\n\r\n321\r\n\r\n\r\nfoobar"代码

 int num1 = sc.nextInt(); int num2 = sc.nextInt(); String name = sc.next(); 

将能够正确分配num1=42 num2=321 name=foobar

而不是input.nextLine()使用input.next() ,这应该解决问题。

修改后的代码

 public static Scanner input = new Scanner(System.in); public static void main(String[] args) { System.out.print("Insert a number: "); int number = input.nextInt(); System.out.print("Text1: "); String text1 = input.next(); System.out.print("Text2: "); String text2 = input.next(); } 

为了避免这个问题,请使用nextLine();nextInt();之后立即nextInt(); 因为它有助于清除缓冲区。 按ENTERnextInt(); 不会捕获新行,因此稍后会跳过Scanner代码。

 Scanner scanner = new Scanner(System.in); int option = scanner.nextInt(); scanner.nextLine(); //clearing the buffer 

如果要快速扫描输入而不混淆Scanner类的nextLine()方法,请使用自定义输入扫描程序。

代码:

 class ScanReader { /** * @author Nikunj Khokhar */ private byte[] buf = new byte[4 * 1024]; private int index; private BufferedInputStream in; private int total; public ScanReader(InputStream inputStream) { in = new BufferedInputStream(inputStream); } private int scan() throws IOException { if (index >= total) { index = 0; total = in.read(buf); if (total <= 0) return -1; } return buf[index++]; } public char scanChar(){ int c=scan(); while (isWhiteSpace(c))c=scan(); return (char)c; } public int scanInt() throws IOException { int integer = 0; int n = scan(); while (isWhiteSpace(n)) n = scan(); int neg = 1; if (n == '-') { neg = -1; n = scan(); } while (!isWhiteSpace(n)) { if (n >= '0' && n <= '9') { integer *= 10; integer += n - '0'; n = scan(); } } return neg * integer; } public String scanString() throws IOException { int c = scan(); while (isWhiteSpace(c)) c = scan(); StringBuilder res = new StringBuilder(); do { res.appendCodePoint(c); c = scan(); } while (!isWhiteSpace(c)); return res.toString(); } private boolean isWhiteSpace(int n) { if (n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1) return true; else return false; } public long scanLong() throws IOException { long integer = 0; int n = scan(); while (isWhiteSpace(n)) n = scan(); int neg = 1; if (n == '-') { neg = -1; n = scan(); } while (!isWhiteSpace(n)) { if (n >= '0' && n <= '9') { integer *= 10; integer += n - '0'; n = scan(); } } return neg * integer; } public void scanLong(long[] A) throws IOException { for (int i = 0; i < A.length; i++) A[i] = scanLong(); } public void scanInt(int[] A) throws IOException { for (int i = 0; i < A.length; i++) A[i] = scanInt(); } public double scanDouble() throws IOException { int c = scan(); while (isWhiteSpace(c)) c = scan(); int sgn = 1; if (c == '-') { sgn = -1; c = scan(); } double res = 0; while (!isWhiteSpace(c) && c != '.') { if (c == 'e' || c == 'E') { return res * Math.pow(10, scanInt()); } res *= 10; res += c - '0'; c = scan(); } if (c == '.') { c = scan(); double m = 1; while (!isWhiteSpace(c)) { if (c == 'e' || c == 'E') { return res * Math.pow(10, scanInt()); } m /= 10; res += (c - '0') * m; c = scan(); } } return res * sgn; } } 

好处 :

  • 扫描输入比BufferReader更快
  • 减少时间复杂性
  • 为每个下一个输入刷新缓冲区

方法 :

  • scanChar() - 扫描单个字符
  • scanInt() - 扫描整数值
  • scanLong() - 扫描长值
  • scanString() - 扫描字符串值
  • scanDouble() - 扫描双值
  • scanInt(int [] array) - 扫描完成数组(整数)
  • scanLong(long [] array) - 扫描完成数组(长)

用法:

  1. 将给定代码复制到您的Java代码下面。
  2. 给定类的初始化对象

ScanReader sc = new ScanReader(System.in); 3.导入必要的类:

import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; 4.从main方法抛出IOException以处理exception5.使用提供的方法。 6.享受

示例:

 import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; class Main{ public static void main(String... as) throws IOException{ ScanReader sc = new ScanReader(System.in); int a=sc.scanInt(); System.out.println(a); } } class ScanReader.... 

如果要读取字符串和整数,解决方案是使用两个扫描程序:

 Scanner stringScanner = new Scanner(System.in); Scanner intScanner = new Scanner(System.in); intScanner.nextInt(); String s = stringScanner.nextLine(); // unaffected by previous nextInt() System.out.println(s); intScanner.close(); stringScanner.close(); 

与解析输入相比, sc.nextLine()更好。 因为表现明智,所以会很好。

我想我参加派对的时间已经很晚了..

如前所述,在获取int值后调用input.nextLine()将解决您的问题。 您的代码无法工作的原因是因为没有其他内容可以从您的输入(您输入int的地方)存储到string1 。 我只是对整个主题稍微透露一点。

nextLine()视为Scanner类中nextFoo()方法中的奇数。 让我们举一个简单的例子..假设我们有两行代码,如下所示:

 int firstNumber = input.nextInt(); int secondNumber = input.nextInt(); 

如果我们输入下面的值(作为单行输入)

54 234

我们的firstNumbersecondNumber变量的值分别变为54和234。 这样工作的原因是因为当nextInt()方法接受值时, 不会自动生成新的换行符( 即\ n )。 它只需要“下一个int”并继续前进。 除了nextLine()之外,其他nextFoo()方法也是如此。

nextLine()在获取值后立即生成新换行符; 这就是@RohitJain所说的新线路被“消耗”的意思。

最后,next()方法只使用最近的String 而不生成新行; 这使得这是在同一行中获取单独字符串的优先方法。

我希望这有帮助..快乐编码!

 public static void main(String[] args) { Scanner scan = new Scanner(System.in); int i = scan.nextInt(); scan.nextLine(); double d = scan.nextDouble(); scan.nextLine(); String s = scan.nextLine(); System.out.println("String: " + s); System.out.println("Double: " + d); System.out.println("Int: " + i); } 

我的测试结果与Prine相同,但我确实想到了一个相当简单的解决方法:

使用BufferedReader#nextLine() ,您将使用Scanner#readLine() ,避免此错误。 您甚至可以使用BufferedReader nextLine函数编写自己的Scanner包装器来覆盖Scanner readLine函数。

为什么不在每次阅读时使用新的扫描仪? 如下。 使用这种方法,您将无法面对您的问题。

 int i = new Scanner(System.in).nextInt();