使用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.nextInt
或Scanner.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"
)
- 回车(CR – 用字符串文字表示为
-
当你从控制台读取数据时,它允许用户输入他的回复,当他完成时,他需要以某种方式确认这一事实。 为此,用户需要按键盘上的“输入”/“返回”键。
重要的是,除了确保将用户数据放置到标准输入 (由
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
viaInteger.parseInt
。
BTW : Scanner#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();
因为它有助于清除缓冲区。 按ENTER
, nextInt();
不会捕获新行,因此稍后会跳过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) - 扫描完成数组(长)
用法:
- 将给定代码复制到您的Java代码下面。
- 给定类的初始化对象
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
我们的firstNumber
和secondNumber
变量的值分别变为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();