问题描述
Scanner.next
系列的输入读取和Scanner.nextLine()
混用时导致读取不到数据。
next nextInt nextDouble nextFloat
和Scanner.nextLine()
连用都会有问题。
例如下面(只输入一次就产生了两个输出,产生Scanner.nextLine()
被跳过的错觉):
Scanner sc=new Scanner(System.in);
int a=sc.nextInt();
String rs=sc.nextLine();
System.out.println("a:"+a);
System.out.println("rs:"+rs);
//控制台输出
//1
//a:1
//rs:
问题分析
- 使用
Scanner.next
系列的输入读取时,首先读取开始
是从有效字符开始的,有效字符前的回车、空格等都不算读取到的内容;当遇到空格、tab、enter回车时,读取结束
。 - 而
Scanner.nextLine()
的读取是以换行符\r\n
(Windows下)结束的。 - 另外,使用
Scanner.next
系列读取输入后,换行符(\r\n
)是被留在缓存区的,而Scanner.nextLine()
读取后,在缓存区的换行符(\r\n
)会被清除,这也说明了为什么混合使用Scanner.next系列
和Scanner.nextLine()
会产生读取不到的问题,因为Scanner.next系列
读取后,留在缓存区的换行符被下一次的Scanner.nextLine
识别到,直接读取结束。
Scanner sc=new Scanner(System.in);
String a=sc.next();
System.out.println("a:"+a);
//控制台输入
// 1234 45 (空格1234空格45)
//输出 a:1234 (无法读取空格)
String a=sc.next();
String rs=sc.nextLine();
System.out.println("a:"+a);
System.out.println("rs:"+rs);
//控制台输入
//1234 45 (1234空格45)
//输出 a:1234
// rs: 45 (rs=空格45 nextLine()是读取到空格了的)
当使用Scanner.next
系列(next、 nextInt 、nextDouble 、nextFloat
)读取输入时,从缓存区读取数据,如输入了 1234,然后回车换行(\r\n
),Scanner.next
读取到了1234,但是回车字符(\r\n
)被留到了缓存区,再使用Scanner.nextLine()
读取数据时,直接返回了换行符(\r\n
)前的数据,因此输入为空。
- 此时再分析上面最开始那个例子,就明白为什么产生了没有输入的现象。
int a=sc.nextInt();
String rs=sc.nextLine();
//缓存区 1换行符(\r\n)
System.out.println("a:"+a); //a:1 缓存区还剩回车符
System.out.println("rs:"+rs); //rs: 识别到换行符,读取结束,输出无
解决方案:
两种解决方案。
- 一种是最简单的,就是避免使用
Scanner.nextLine()
和Scanner.next系列
的混用,导致产生无输入。 - 另一种是混用时,在使用
Scanner.next系列
读取输入后,先使用Scanner.nextLine()
读取一次,去掉缓存区的换行符,再使用一次Scanner.nextLine()
输入想要的字符串。
//目的:接收到输入123和abc
Scanner sc=new Scanner(System.in);
String a=sc.next();
sc.nextLine(); //去除缓存区的换行符
String rs=sc.nextLine();
System.out.println("a:"+a);
System.out.println("rs:"+rs);
//控制台:
//输入
//123
//abc
//输出
//a:123
//rs:abc
//使用 变量s 更容易理解 读取不到输入的现象
Scanner sc=new Scanner(System.in);
String a=sc.next();
String s=sc.nextLine();
String rs=sc.nextLine();
System.out.println("a:"+a);
System.out.println("s:"+s);
System.out.println("rs:"+rs);
//输入不变,输出
//a:123
//s:
//rs:abc
查阅官方API文档 nextLine():
public String nextLine()
Advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line,excluding any line separator at the end. The position is set to the beginning of the next line.
Since this method continues to search through the input looking for a line separator, it may buffer all of the input searching for the line to skip if no line separators are present.
Returns: the line that was skipped Throws:
NoSuchElementException - if no line was found IllegalStateException - if this scanner is closed
上面这段话是说 nextLine()这个扫描器是从每行开始进行扫描,直到识别到行尾的分隔符,输出开始到分隔符间的内容,不包括分隔符。然后把扫描器的位置置于下一行的开始。