问题一:循环创建Scanner对象并使用close()方法
菜鸟想要用Scanner达到循环输入的目的,没有直接百度而是“自以为是”的在循环里写创建Scanner类,并且还“体贴”的在使用完毕后close()掉:
for(int i = 0; i < 3; i++) {
System.out.println("第"+(i+1)+"次输入");
Scanner sc = new Scanner(System.in);
String strInput = sc.next();
sc.close();
}
然而,在循环到第二次的时候就不对了:
试了半天,最后老实问度娘:Scanner + java.util.NoSuchElementException
原来是因为第二次循环sc.next()找不到下一个元素,找不到的原因是因为上次循环结束时关闭了System.in。
“System.in 在java中是静态变量,当前类所有的scanner对象共享它,当一个scanner对象执行close()操作后,其他所有的scanner对象都不可用了。”
正确姿势:
Scanner sc = new Scanner(System.in);
for(int i = 0; i < 3; i++) {
System.out.println("第"+(i+1)+"次输入");
String strInput = sc.next();
}
sc.close();
把开头结尾丢循环外面就对了~
问题二:循环输入校验时不处理校验失败的部分
之所以要循环输入是因为想要做校验,输入不通过就继续输入。比如:判断输入的类型;输入是否在规定范围内等。
判断输入的类型可以用Scanner的hasNextInt()、hasNextDouble()等,其中hasNext()就是判断是否有下一次输入的内容,不管类型,其他的都是判断是否有下一个相应类型的输入。比如输入一个整数:
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请输入一个整数:");
if(sc.hasNextInt()) {
int intInput = sc.nextInt();
System.out.println("输入的整数为:"+intInput);
break;
}
}
sc.close();
问题不是有值怎样,而是没有值怎么处理,如果输入的是"abc",我以为的结果是接着下一次输入就好了,然而事实是:
进入了死循环…我在sc.hasNextInt()那行打了断点,发现进入if之后,第一次程序会等待我输入内容,后面就不等我输入了,直接判断不符合if条件。
“遇到hasNext()时,Scanner也会阻塞,等待你输入,等你输入后返回true。查看jdkapi,你会发现该方法当Scanner缓存区中有值可读时,会返回true,若没有,会一直阻塞等待你输入。”
“hasNextInt()函数大体意思表示scanner当前的标记的输入是否为int,并不会自动的移动标记。”
也就是说,若输入的是整数,进入if代码块,执行了hasNextInt()方法会改变读取的标记位置;若输入的不是整数,没有执行类似hasNext()之类的方法,缓存区里将会放着上次的输入内容,从而一直if条件不满足。
解决方法就是:hasNext()之类的方法,要和next()之类的方法搭配使用:
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请输入一个整数:");
if(sc.hasNextInt()) {
int intInput = sc.nextInt();
System.out.println("输入的整数为:"+intInput);
break;
}else {
sc.next();
}
}
sc.close();
其他用法
- 终止输入:要么在控制台 ctrl+z,要么约定一个输入的字符串作为终止符,写在循环条件里
- 实际上每行输入结尾应该都带着"\n",通过nextInt()、nextDouble()等只能读取数值,是不包含那个回车的,这时候再接一个nextLine()你将成功获取到一个回车~
- next()方法由第一个有效字符(非空格,非换行符) 开始,到第一个分隔符或结束符(空格或换行符) 结束,从而获得第一个扫描到的不含空格、换行符的单个字符串。换言之,如果想要获取带空格的内容,就用nextLine()
- 关于光标cursor位置:
nextInt() - 光标位置在数值后面,"\n"前面;
next() - 光标指向本行;
nextLine() - 光标指向下一行