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()
此掃描器執行當前行,並返回跳過的輸入資訊。
三、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,文字檔案的內容如下:老趙,28,feb-01,true小竹,22,dec-03,false阿波,21,dec-03,false凱子,25,dec-03,true 程式:
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()之上即可。