本文转载自:
java中的Scanner
百度经验:Java中Scanner类的用法
Java Scanner类报错java.util.NoSuchElementException
一、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() :此扫描器执行当前行,并返回跳过的输入信息。
三、Scanner类实例
(1)
import java.util.*;
public class Example
{
public static void main(String args[])
{
System.out.println("请输入若干个数,每输入一个数用回车确认");
System.out.println("最后输入一个非数字结束输入操作");
Scanner reader=new Scanner(System.in);
double sum=0;
int m=0;
while(reader.hasNextDouble())
{
double x=reader.nextDouble();
m=m+1;
sum=sum+x;
}
System.out.printf("%d个数的和为%f\n",m,sum);
System.out.printf("%d个数的平均值是%f\n",m,sum/m);
}
}
运行结果:
C:\java>java
请输入若干个数,每输入一个数用回车确认
最后输入一个非数字结束输入操作
34.13445
3个数的和为113.100000
3个数的平均值是37.700000
(2)读取并分析文本文件:hrinfo.txt
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
public class readhuman {
private static void readfile(String filename) {
try {
Scanner scanner = new Scanner(new File(filename));
scanner.useDelimiter(System.getProperty("line.separator"));
while (scanner.hasNext()) {
parseline(scanner.next());
}
scanner.close();
}catch (FileNotFoundException e) {
System.out.println(e);
}
}
private static void parseline(String line) {
Scanner linescanner = new Scanner(line);
linescanner.www.gzlij.com useDelimiter(",");
//可以修改usedelimiter参数以读取不同分隔符分隔的内容
String name = linescanner.next();
int age = linescanner.nextInt();
String idate = linescanner.next();
boolean iscertified = linescanner.nextBoolean();
System.out.println("姓名:"+name+" ,年龄:"+ age+" ,入司时间:"+ idate+" ,验证标记:"+iscertified );
}
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("usage: java readhuman file location");
System.exit(0);
}
readfile(args[0]);
}
}
运行结果:C:\java>java readhuman hrinfo.txt
姓名:老赵 ,年龄:28 ,入司时间:feb-01 ,验证标记:true
姓名:小竹 ,年龄:22 ,入司时间:dec-03 ,验证标记:false
姓名:阿波 ,年龄:21 ,入司时间:dec-03 ,验证标记:false
姓名:凯子,年龄:25 ,入司时间:dec-03 ,验证标记:true
(3)Scanner默认使用空格作为分割符来分隔文本,但允许你指定新的分隔符
使用默认的空格分隔符:
public static void main(String[] args) throws FileNotFoundException {
Scanner s = new Scanner("123 asdf sd 45 789 sdf asdfl,sdf.sdfl,asdf ......asdfkl las");
// s.useDelimiter(" |,|\\.");
while (s.hasNext()) {
System.out.println(s.next());
}
}
运行结果:
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方法里面有以下代码。
try {
n = source.read(buf);
} catch (IOException ioe) {
lastException = ioe;
n = -1;
}
if (n == -1) {
sourceClosed = true;
needInput = false;
}
因为读到了-1就设置sourceClosed =true;neepinput=false; 在next方法里面有以下代码:
if (needInput)
readInput();
else
throwFor();
当needinput为false,就执行throwFor,因此再看throwFor
skipped = false;
if ((sourceClosed) && (position == buf.limit()))
throw new NoSuchElementException();
else
throw new InputMismatchException();
position 是当前读取的内容在缓冲区中位置,因为读取的是-1,因此position =0,而buf.limit()也等于0,因此就执行了throw new NoSuchElementException();
【解决方案】将input1.close()放在input2.close()之上即可。