1. 概述
在Java中,我们可以使用Integer.parseInt(Scanner.nextLine())
和Scanner.nextInt()
两种方式从Scanner
读取整数。然而,这两种方法之间存在一些差异。
在这个教程中,我们将比较它们,并讨论它们的不同之处。
2. 使用Integer.parseInt(scanner.nextLine())
和scanner.nextInt()
读取整数
Scanner.nextLine()
方法会从扫描器读取整个行作为字符串。因此,如果我们希望结果是Integer
类型,我们必须自己将字符串转换为Integer
,例如使用Integer.parseInt()
方法。
另一方面,Scanner.nextInt()
会读取输入流中的下一个标记作为整数。Scanner
中的一个标记由解析输入流时使用的分隔模式定义。默认情况下,Scanner
的分隔模式是任何空白字符(如空格、制表符或换行符)。
现在我们了解了这两个方法的作用。接下来,让我们看看它们如何从Scanner
对象读取整数。首先,我们给扫描器提供一个带有换行符的字符串:
String input = "42\n";
为了简化,我们在本教程中使用单元测试断言来验证结果。
首先,使用Scanner.nextLine()
获取数字42:
Scanner sc1 = new Scanner(input);
int num1 = Integer.parseInt(sc1.nextLine());
assertEquals(42, num1);
接下来轮到Scanner.nextInt()
:
Scanner sc2 = new Scanner(input);
int num2 = sc2.nextInt();
assertEquals(42, num2);
正如上面的两个测试所示,两种方法都能从Scanner
对象正确地读取输入并获取整数42。
下面我们来看看这两种方法之间的区别。
3. 当输入格式不正确时
它们的第一个差异在于,当输入不是一个有效的数字时,两种方法会抛出不同的异常。
现在,改变输入:
String input = "Nan\n";
当我们使用scanner.nextLine()
读取输入并尝试将无效输入转换为整数时,它会抛出**NumberFormatException
**:
Scanner sc1 = new Scanner(input);
assertThrows(NumberFormatException.class, () -> Integer.parseInt(sc1.nextLine()));
这是因为sc1.nextLine()
将读取下一行输入作为字符串。但后续的转换失败,所以Integer.parseInt()
方法抛出了NumberFormatException
。
值得一提的是,我们使用了JUnit 5的assertThrows()
方法来断言方法调用会抛出NumberFormatException
。
另一方面,当我们尝试使用Scanner.nextInt()
读取输入作为整数时,它会引发**InputMismatchException
**:
Scanner sc2 = new Scanner(input);
assertThrows(InputMismatchException.class, sc2::nextInt);
4. Scanner.nextInt()
方法不会消耗无效的标记
如前所述,Scanner.nextLine()
会读取输入流中的下一行作为字符串。与Scanner.nextLine()
不同,nextInt()
会尝试将输入流中的下一个标记解析为整数。
如果它无法解析一个标记,如之前所述,nextInt()
会抛出InputMismatchException
。但值得注意的是,Scanner.nextInt()
并不会消费解析失败的标记。
下面的例子可以帮助我们快速理解这一点:
String input = "42 is a magic number\n";
// nextInt()
Scanner sc2 = new Scanner(input);
int num2 = sc2.nextInt();
assertEquals(42, num2);
// calling nextInt() again on "is" raises the exception
assertThrows(InputMismatchException.class, sc2::nextInt);
String theNextToken = sc2.next();
assertEquals("is", theNextToken);
如上例所示,输入字符串有五个标记。第一个是“42",这是一个有效的整数。正如预期,sc2.nextInt()
获取了整数42
。然后,我们再次调用nextInt()
并尝试将标记“is"解析为整数。这会抛出InputMismatchException
,这也是我们的预期。
接下来,我们调用sc2.next()
获取下一个标记作为字符串。我们可以看到,刚才nextInt()
方法未能解析的标记“is"被读取到了输入中。换句话说,“is"并没有被sc2.nextInt()
方法消费。
5. 换行处理
Java Scanner默认通过“\n”字符分隔行。接下来,让我们看看Scanner.nextLine()
和nextInt()
如何处理换行字符。
首先,准备一个多行字符串作为输入:
String input = new StringBuilder().append("42\n")
.append("It is a magic number.\n")
.toString();
Scanner.nextLine()
方法会消耗整行,包括行分隔符。但它只返回没有末尾换行符的文本,并将位置设置在下一行的开始。
// nextLine()
Scanner sc1 = new Scanner(input);
int num1 = Integer.parseInt(sc1.nextLine());
String nextLineText1 = sc1.nextLine();
assertEquals(42, num1);
assertEquals("It is a magic number.", nextLineText1);
然而,另一方面,Scanner.nextInt()
会扫描输入流中的下一个整数标记,而不消耗其后的换行字符:
// nextInt()
Scanner sc2 = new Scanner(input);
int num2 = sc2.nextInt();
assertEquals(42, num2);
// nextInt() leaves the newline charater (\n) behind
String nextLineText2 = sc2.nextLine();
assertEquals("", nextLineText2);
在这个测试中,我们先使用sc2.nextInt()
获取了数字42,然后调用sc2.nextLine()
。然后,我们可以看到,方法返回的是空字符串而不是“It is a magic number.”。这是因为nextInt()
在“42"之后不会消费换行字符。
6. 总结
在这篇文章中,我们通过示例讨论了Integer.parseInt(Scanner.nextLine())
和Scanner.nextInt()
之间的差异。以下是总结:
- 对于格式不正确的输入,两种方法会抛出不同类型的异常。
Scanner.nextLine()
会消耗Scanner
中的换行字符,但返回的字符串不包含它。Scanner.nextInt()
不会消耗换行字符。Scanner.nextInt()
不会消费无法解析的标记。
如往常一样,这里展示的所有代码片段都在GitHub上可用。