一、Scanner 简介

Java 5 添加了 java.util.Scanner 类,这是一个用于扫描输入文本的新的实用程序。它是以前的 StringTokenize r和 Matcher 类之间的某种结合。由于任何数据都必须通过同一模式的捕获组检索或通过使用一个索引来检索文本的各个部分。于是可以结合使用正则表达式和从输入流中检索特定类型数据项的方法。这样,除了能使用正则表达式之外,Scanner 类还可以任意地对字符串和基本类型(如 int 和 double )的数据进行分析。借助于 Scanner,可以针对任何要处理的文本内容编写自定义的语法分析器。

二、关于 nextInt()、next() 和 nextLine() 的理解

1、nextInt(): it only reads the int value, nextInt() places the cursor(光标) in the same line after reading the input.(nextInt()只读取数值,剩下"\n"还没有读取,并将 cursor 放在本行中)

2、next(): read the input only till the space. It can’t read two words separated by space. Also, next() places the cursor in the same line after reading the input.(next()只读空格之前的数据,并且 cursor 指向本行)
next() 方法遇见第一个有效字符(非空格,非换行符)时,开始扫描,当遇见第一个分隔符或结束符(空格或换行符)时,结束扫描,获取扫描到的内容,即获得第一个扫描到的不含空格、换行符的单个字符串。

3、nextLine(): reads input including space between the words (that is, it reads till the end of line \n). Once the input is read, nextLine() positions the cursor in the next line.  nextLine() 时,则可以扫描到一行内容并作为一个字符串而被获取到。

next 和 nextLine() 的区别 

public class NextTest {

    public static void main(String[] args) {
        String s1, s2;
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入第一个字符串:");
        s1 = sc.nextLine();
        System.out.println("请输入第二个字符串:");
        s2 = sc.next();
        System.out.println("输入的字符串是:" + s1 + " " + s2);
    }
}
  • 输出
请输入第一个字符串:
hello
请输入第二个字符串:
world
输入的字符串是:hello world

将上面代码中的 next() 方法和 nextLine() 方法位置互换下:

public class NextTest {

    public static void main(String[] args) {
        String s1, s2;
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入第一个字符串:");
        s1 = sc.next();
        System.out.println("请输入第二个字符串:");
        s2 = sc.nextLine();
        System.out.println("输入的字符串是:" + s1 + " " + s2);
    }
}
  •  输出
请输入第一个字符串:
hello
请输入第二个字符串:
输入的字符串是:hello

可以看到,nextLine() 自动读取了被 next() 去掉的 Enter 作为他的结束符,所以没办法给 s2 从键盘输入值。经过验证,我发现其他的 next 的方法,如 double nextDouble() , float nextFloat() , int nextInt() 等与 nextLine() 连用时都存在这个问题,解决的办法是:在每一个 next()、nextDouble() 、 nextFloat()、nextInt() 等语句之后加一个 nextLine() 语句,将被 next() 去掉的 Enter 结束符过滤掉。

public class NextTest {

    public static void main(String[] args) {
        String s1, s2;
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入第一个字符串:");
        s1 = sc.next();
        sc.nextLine();
        System.out.println("请输入第二个字符串:");
        s2 = sc.nextLine();
        System.out.println("输入的字符串是:" + s1 + " " + s2);
    }
}
  • 输出 
请输入第一个字符串:
hello
请输入第二个字符串:
world
输入的字符串是:hello world

三、循环输入多组测试用例

一个 while 就是一个测试用例。

public class NextTest {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);

        // 一个 while 就是一个测试用例
        while(sc.hasNext()){
            int n = sc.nextInt();   // 该测试用例后序接收多少参数
            String[] arrayStr = new String[n];

            for(int i = 0; i < n; i++){
                arrayStr[i] = sc.next();
            }
            System.out.println(Arrays.toString(arrayStr));
        }
    }
}
  •  输出
3
a
b
c
[a, b, c]

一个与容器结合的综合例子:

public class NextTest {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);

        // 一个 while 就是一个测试用例
        while(sc.hasNext()){
            int n = sc.nextInt();   // 该测试用例后序接收多少参数

            // 如果没有该行,则执行第一个sc.nextLine()命令时的返回值是int n = sc.nextInt()的值
            sc.nextLine();
            HashSet<String> set = new HashSet<String>();

            for(int i = 0; i < n; i++){
                String line = sc.nextLine();
                String[] arr = line.split(" ");
                for(int j = 0; j < arr.length; j++){
                    set.add(arr[j]);
                }
            }
            System.out.println("sum:" + set.size());
        }
    }
}
  • 运行结果
3
a b c
d e f
g h i
sum:9