即使没有下一行可用,java.util.Scanner.hasNextLine()也返回true

时间:2016-09-08 12:58:50

标签: java java.util.scanner

假设以下代码:

String example = "  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode\n" +
    "   0: 00000000:04D2 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 15662 1 ffff8800baf1c780 100 0 0 10 0\n" +
    "   1: 00000000:04D2 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 15662 1 ffff8800baf1c780 100 0 0 10 0";

Scanner scanner = new Scanner(example);
scanner.useRadix(16).useDelimiter("[\\s:]+");

while (scanner.hasNextLine()) {
    scanner.nextLine(); // skip header on first iteration, which is not needed
    int slot = scanner.nextInt();
    System.out.println(slot);
}

我基本上读取除标题之外的每一行的第一个整数。我期待看到以下输出:

0
1

但抛出异常:

java.util.NoSuchElementException
  at java.util.Scanner.throwFor(Scanner.java:862)
  at java.util.Scanner.next(Scanner.java:1485)
  at java.util.Scanner.nextInt(Scanner.java:2117)
  at java.util.Scanner.nextInt(Scanner.java:2076)

问题是为什么Scanner.hasNextLine()会在最后一行返回true,显然流中没有新行?

1 个答案:

答案 0 :(得分:0)

这在输入结束时发生。您解析1,它会离开它后面的空格。那么你的循环条件仍然是正确的(有可用的行),所以你读取了这一行,它留在你的字符串的最后。然后,在没有检查的情况下,您尝试读取int。所以它失败了。你需要检查是否有可用的int,因为在最后一行,没有。

这是一个版本,检查是否有可用的int,并显示您正在跳过的内容,这应该会让事情变得更清晰(live copy):

String example = "  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode\n" +
    "   0: 00000000:04D2 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 15662 1 ffff8800baf1c780 100 0 0 10 0\n" +
    "   1: 00000000:04D2 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 15662 1 ffff8800baf1c780 100 0 0 10 0";

Scanner scanner = new Scanner(example);
scanner.useRadix(16).useDelimiter("[\\s:]+");
Set<Integer> result = new HashSet<>();
scanner.next();

while (scanner.hasNextLine()) {
    String skipped = scanner.nextLine();
    System.out.println("Skipped: " + skipped); // skip header on first iteration and also skips remainder of previous line after we read the int
    if (scanner.hasNextInt()) {
        int slot = scanner.nextInt();
        System.out.println(slot);
    } else {
        System.out.println("No int avaialble");
    }
}

System.out.println("Done");

我已经为跳过的内容添加了System.out.println,但实际上您要做的就是在调试器中逐步执行此操作。

这是它输出的内容:

Skipped:   local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
0
Skipped: : 00000000:04D2 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 15662 1 ffff8800baf1c780 100 0 0 10 0
1
Skipped: : 00000000:04D2 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 15662 1 ffff8800baf1c780 100 0 0 10 0
No int avaialble
Done

现在,上面的内容有点复杂,因为您在一个循环中读取了部分行(开头的int)但是在开头读取了行的其余部分(int之后的部分)下一个循环。理想情况下,您可以在同一个循环(live copy)中清理它们:

String example = "  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode\n" +
    "   0: 00000000:04D2 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 15662 1 ffff8800baf1c780 100 0 0 10 0\n" +
    "   1: 00000000:04D2 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 15662 1 ffff8800baf1c780 100 0 0 10 0";

Scanner scanner = new Scanner(example);
scanner.useRadix(16).useDelimiter("[\\s:]+");
Set<Integer> result = new HashSet<>();
scanner.next();

if (scanner.hasNextLine()) {
    // Skip the headers
    scanner.nextLine();
}
// Process records
while (scanner.hasNextLine()) {
    // The first int
    if (scanner.hasNextInt()) {
        int slot = scanner.nextInt();
        System.out.println(slot);

        // Read anything else you want from that line, until
        // you have only the newline left (or any trailing characters
        // you don't want to process and then the newline)
    }

    // Clear the newline
    scanner.nextLine();
}

System.out.println("Done");

输出:

0
1
Done