Scanner为我们提供了多个next*()方法来从键盘或文件等输入源读取不同类型的数据,像next*()这类方法都称为令牌读取方法,因为它们会读取用分隔符分隔开的令牌。默认的分隔符为空格,当然我们也可以使用Scanner的useDelimiter(String pattern)方法自定义分隔符模式。
首先我们要先来看看这里的令牌指的是什么?这里举个例子,我用Scanner读取目录下scanner.txt文件中的数据:
scanner.txt中就一行字符串
将其置于某个目录下,这里我放在H盘的根目录下
上面就是项目结构,很简单就一个类,代码如下:
package com.aigestudio.test; import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; public class ScannerTest { public static void main(String[] args) throws FileNotFoundException { File file = new File("H:\\scanner.txt"); Scanner input = new Scanner(file); while (input.hasNext()) { String strA = input.next(); System.out.println(strA); String strB = input.next(); System.out.println(strB); } input.close(); } }
运行后可以在控制台看到输出结果:
可以看到我们通过先后两次next()方法分别读取了分隔符(默认是空格)前后的字符数组"Enjoy"和"Java!",而上面所说的令牌即是这两个字符数组。
像next*()(比方说上面的next())这样的令牌读取方法在读取数据(scanner.txt文件中的数据)时首先会跳过任意分隔符(默认是空格),然后读取一个以分隔符结束的令牌("Enjoy")。然后,对应于nextByte()、nextShort()、nextInt()、nextLong()、nextFloat()和nextDouble()方法这个令牌就会分别被自动转换成byte、short、int、long、float、double等相对应的类型值,而对于next()方法而言则无需作转换,如果令牌和期望的类型不匹配,例如在上面的代码中把next()改为nextInt():
package com.aigestudio.test; import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; public class ScannerTest { public static void main(String[] args) throws FileNotFoundException { File file = new File("H:\\scanner.txt"); Scanner input = new Scanner(file); while (input.hasNext()) { int strA = input.nextInt(); System.out.println(strA); int strB = input.nextInt(); System.out.println(strB); } input.close(); } }
这时则会抛出一个运行异常:java.util.InputMismatchException:
令牌读取方法不能读取令牌后面的分隔符,比如第一段代码的第一个next()方法我们读取了"Enjoy"但并没有包括其后的空格。如果在令牌读取方法之后调用nextLine(),该方法读取从这个分隔符开始到这行的行分隔符结束的字符,这个行分隔符也被读取,但是它不是nextLine()返回的字符串部分,比如我将scanner.txt文件改动下:
这时该行数据中有三个空格,我们用第一段代码改动下:
package com.aigestudio.test; import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; public class ScannerTest { public static void main(String[] args) throws FileNotFoundException { File file = new File("H:\\scanner.txt"); Scanner input = new Scanner(file); while (input.hasNext()) { String strA = input.next(); System.out.println(strA); String strB = input.nextLine(); System.out.println(strB); } input.close(); } }
运行后显示结果如下:
可以看到nextLine()方法读取了next()方法之后该行换行符前所有的数据,包括空格!
那么,为什么我们不建议在调用其他next*()方法后调用nextLine()方法呢?其实从上面的测试中大家也会有所了解,nextLine()方法有时会读取到一些我们并不想要的结果。比如下面代码:
package com.aigestudio.test; import java.io.FileNotFoundException; import java.util.Scanner; public class ScannerTest { public static void main(String[] args) throws FileNotFoundException { Scanner input = new Scanner(System.in); String strA = input.next(); System.out.println("strA:" + strA); String strB = input.nextLine(); System.out.println("strB:" + strB); input.close(); } }
我们通过Scanner读取从控制台输入的数据,这里我就随便敲了几个字符,按下回车后发现直接输出了两次结果:
这是为什么呢?原因很简单,这里我分解下我输入的过程:运行代码后我一次在键盘上敲下'a'、'd'、'a'……中间的就不写出来了 = =……'d'、'a'、's'、回车;首先next()读取了分隔符(这里的分隔符就是换行符,这种情况下换行符可以当作一个空格)前的那一串乱七八糟的字符,然后紧接着调用nextLine()方法等待我们敲下回车作为行分隔符以读取数据,本来这里是有个“等待”过程的,也就是说我们没敲回车前数据是不该被读取的,但是,在调用next()方法后nextLine()方法前我们却敲下了回车!这里nextLine()被执行,返回了从字符数组最后一个's'到行分隔符(回车)之前的数据!那么在其之间有什么数据呢?没有!空的!所以就有上面我们的输出结果!
说到这里,想必大家应该明白了吧~不懂或者还有什么疑问的可以回复或者加群讨论