Java Scanner用法详解
一、Scanner类简介
Java 5添加了java.util.Scanner类,这是一个用于扫描输入文本的新的实用程序。它是以前的StringTokenizer和Matcher类之间的某种结合。由于任何数据都必须通过同一模式的捕获组检索或通过使用一个索引来检索文本的各个部分。于是可以结合使用正则表达式和从输入流中检索特定类型数据项的方法。这样,除了能使用正则表达式之外,Scanner类还可以任意地对字符串和基本类型(如int和double)的数据进行分析。借助于Scanner,可以针对任何要处理的文本内容编写自定义的语法分析器。
二、Scanner类用法
Scanner是SDK1.5新增的一个类,可使用该类创建一个对象。
Scanner reader=new Scanner(System.in);
然后reader对象调用下列方法(函数),读取用户在命令行输入的各种数据类型
next.Byte(),nextDouble(),nextFloat,nextInt(),nextLine(),nextLong(),nextShot()
上述方法执行时都会造成堵塞,等待用户在命令行输入数据回车确认.例如,拥护在键盘输入12.34,hasNextFloat()的值是true,而hasNextInt()的值是false。NextLine()等待用户输入一个文本行并且回车,该方法得到一个String类型的数据。
Scanner的构造器支持多种方式,可以从字符串(Readable)、输入流、文件等等来直接构建Scanner对象,有了Scanner了,就可以逐段(根据正则分隔式)来扫描整个文本,并对扫描后的结果做想要的处理。
下面是一些API函数的用法:
delimiter()
返回此 Scanner 当前正在用于匹配分隔符的 Pattern。
hasNext()
判断扫描器中当前扫描位置后是否还存在下一段。(原APIDoc的注释很扯淡)
hasNextLine()
如果在此扫描器的输入中存在另一行,则返回 true。
next()
查找并返回来自此扫描器的下一个完整标记。
nextLine()
此扫描器执行当前行,并返回跳过的输入信息。
此处重点讲一下next()和nextLine()的区别
next():只读取输入直到空格。它不能读两个由空格或符号隔开的单词。此外,next()在读取输入后将光标放在同一行中。(next()只读空格之前的数据,并且光标指向本行)
nextLine():读取输入,包括单词之间的空格和除回车以外的所有符号(即。它读到行尾)。读取输入后,nextLine()将光标定位在下一行
三、Scanner类实例
(1)
1 import java.util.*; 2 3 public class demo { 4 public static void main(String args[]) { 5 System.out.println("请输入若干个数,每输入一个数用回车确认"); 6 System.out.println("最后输入一个非数字结束输入操作"); 7 Scanner reader = new Scanner(System.in); 8 double sum = 0; 9 int m = 0; 10 while (reader.hasNextDouble()) { 11 double x = reader.nextDouble(); 12 m = m + 1; 13 sum = sum + x; 14 } 15 System.out.printf("%d个数的和为%f\n", m, sum); 16 System.out.printf("%d个数的平均值是%f\n", m, sum / m); 17 reader.close(); 18 } 19 }
运行结果:
请输入若干个数,每输入一个数用回车确认 最后输入一个非数字结束输入操作 7.8 6.6 3 end 3个数的和为17.400000 3个数的平均值是5.800000
(2)Scanner默认使用空格作为分割符来分隔文本,但允许你指定新的分隔符
使用默认的空格分隔符:
1 import java.util.Scanner; 2 3 public class demo { 4 public static void main(String[] args) { 5 Scanner s = new Scanner("123 asdf sd 45 789 sdf asdfl,sdf.sdfl,asdf ......asdfkl las"); 6 // s.useDelimiter(" |,|\\."); 7 while (s.hasNext()) { 8 System.out.println(s.next()); 9 } 10 } 11 }
运行结果:
123 asdf sd 45 789 sdf asdfl,sdf.sdfl,asdf ......asdfkl las
--将注释行去掉,使用空格或逗号或点号作为分隔符,输出结果如下:
123 asdf sd 45 789 sdf asdfl sdf sdfl asdf asdfkl las
四、Scanner报错:java.util.NoSuchElementException
【问题描述】代码如下:
String str1 = input1.nextLine(); input1.close(); Scanner input2 = new Scanner(System.in); String str2 = input2.nextLine(); input2.close();
【报错原因】在第二次使用Scanner之前调用了close方法。而在关闭的时候,会把System.in也关闭了。当下次new一个读取的时候,因为输入流已经关闭,所以读取的值就是-1;在Scanner 的readinput方法里面有以下代码。
1 try { 2 n = source.read(buf); 3 } catch (IOException ioe) { 4 lastException = ioe; 5 n = -1; 6 } 7 8 if (n == -1) { 9 sourceClosed = true; 10 needInput = false; 11 }
因为读到了-1就设置sourceClosed =true;neepinput=false;
在next方法里面有以下代码:
1 if (needInput) 2 readInput(); 3 else 4 throwFor();
当needinput为false,就执行throwFor,因此再看throwFor
1 skipped = false; 2 if ((sourceClosed) && (position == buf.limit())) 3 throw new NoSuchElementException(); 4 else 5 throw new InputMismatchException();
position 是当前读取的内容在缓冲区中位置,因为读取的是-1,因此position =0,而buf.limit()也等于0,因此就执行了throw new NoSuchElementException();
【解决方案】将input1.close()放在input2.close()之上即可。