现在的位置: 首页 > 综合 > 正文

Scanner工作流程:为何不建议在调用其他next*()方法后调用nextLine()方法?

2016年12月14日 ⁄ 综合 ⁄ 共 2997字 ⁄ 字号 评论关闭

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'到行分隔符(回车)之前的数据!那么在其之间有什么数据呢?没有!空的!所以就有上面我们的输出结果!

说到这里,想必大家应该明白了吧~不懂或者还有什么疑问的可以回复或者加群讨论

抱歉!评论已关闭.