hasNext()和hasNextLine()
hasNextLine()和nextLine()
hasNextLine()方法
同樣看一些說明文檔中對方法的描述:
如果在掃描器的輸入中還有另外一行,就傳回true,事實上同樣沒有傳回fasle的情況,如果沒有另外一行了,就會阻塞,等待你的輸入。
兩個容易出錯的問題
問題1:hasNextLine() 和 next() 混用
首先看一下以下代碼:如果啟動代碼後,在控制台輸入
hello回車
,會進入幾次while循環的代碼段中呢?
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
while (scan.hasNextLine()) {
String str = scan.next();
System.out.println(str);
}
}
}
表面上來說,隻會進入1次,首先在
while (scan.hasNextLine())
中阻塞,系統等待我的輸入,輸入
hello回車
之後,自然就進入了循環體,str擷取到了hello,并把他輸出,又重新回到while循環的判斷語句中,因為我們隻輸入了一行,是以輸入流中沒有另外一行了,就會重新阻塞在while循環判斷中,系統等待我的輸入。然而這種了解是錯誤的
實際上,會進入2次while循環,并且,第二次會在
String str = scan.next()
處阻塞,等待我們的輸入。
這要怎麼了解呢?個人是這麼了解的,當我們第一次輸入
hello回車
之後,
while (scan.hasNextLine())
判斷為真,就第一次進入了循環體中,
String str = scan.next();
讀取輸入流中一個字元串,遇到空白(回車、空格、Tab)就截止,是以str被指派為
hello
,再次回到
while (scan.hasNextLine())
因為這裡是
hasNextLine()
而在hello後面可以想象成有一個
\n
,那麼
hasNextLine()
會認為
\n
是一個空行,再次判斷為真,進入循環體,但是
next()
會自動忽略第一個有效字元前的空白符,是以會在
String str = scan.next();
阻塞,等待我們的輸入。
如果我們将循環的判斷語句改為
while (scan.hasNext())
,那麼就隻會進入一次while循環,第二次會阻塞在
while (scan.hasNext())
中,系統等待我們的輸入。
為此,大家可以通過下圖的方式進行調試,一步一步的跟蹤代碼:
簡單來說:
- 在讀取完了有效字元之後,hasNext() 會認為之後沒有有效字元了,就會阻塞
- 而hasNextLine(),會把有效字元後面的
作為新的一行,傳回真\n
如果我們用這種代碼錯誤的認為他隻會進入一次while循環,并且在
while (scan.hasNextLine())
處等待我新的輸入,在oj系統上就會報錯。
為此解決的辦法就是,要統一起來,前面用hasNextLine() 後面就用nextLine()。
問題2:緊跟在next() 後面的 nextLine() 是無法讀取到有效值的
同樣舉個例子:
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String str1 = scan.next();
System.out.println(str1);
String str2 = scan.nextLine();
System.out.println(str2);
}
}
這個代碼我想實作的功能是,在
String str1 = scan.next();
擷取一個字元串(沒有空格),在
String str2 = scan.nextLine();
擷取一行字元串(可能包含空格)。但是無法實作這個功能,當我們輸入
hello回車
之後,程式就結束了。str2是一個空串(長度 = 0)
這是因為:當我在流中輸入
hello回車
之後,str1讀走了hello,雖然hasNextLine() 會把後面的\n當成是1行,是以不會在
String str2 = scan.nextLine();
這邊阻塞,但是這一行是為空的,是以nextLine()捕獲到的就是一個空串。
下面的代碼更好地說明了這個問題
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String str1 = scan.next();
System.out.println(str1);
if (scan.hasNextLine())
System.out.println(1);
String str2 = scan.nextLine();
if (str2 != null && str2.equals(""))
System.out.println(3);
}
}
提示:
- scan.hasNext()和scan.next() 在是否阻塞上有同樣的效果,如果此時流中存在有效字元,那麼前者傳回true,後者讀取這個有效字元(串);反之,如果目前流中不存在有效字元(串),前者不會傳回false,而是會阻塞,後者同樣會阻塞,等待輸入。
- 但是還是建議在next()擷取之前用hasNext()進行判斷。
- 問題1和問題2的關鍵在于,當有效字元輸入完了之後,用hasNextLine()判斷的話會傳回True,這就導緻了在oj環境下,問題1進入循環,但是next()讀不到值報錯;問題2中next()讀完了之後(有效字元讀完了之後),nextLine()會直接讀取而不會阻塞。