Scanner.nextLine忽略空格? Java

问题描述

我有一个命令行游戏,正在用JUnit进行测试,这是测试:

@Test
  public void testBattle() throws IOException{
    String input = "go forward\ngo left\ntake Pointy Stick\ngo backward\ngo " +
            "right\nnormal attack\nnormal attack\nquit\n";
    provideInput(input);
    actual = new File("src/main/testFiles/testBattle.txt");
    expected = new File("src/main/testFiles/testBattleExpected.txt");
    PrintStream o = new PrintStream(actual);
    System.setout(o);

    ui.gameLoop();
    assertTrue(FileUtils.contentEqualsIgnoreEOL(actual,expected,null));

  }

这是提供输入法:

 private void provideInput(String data) {
    String newdata = data.trim();
    testIn = new ByteArrayInputStream(newdata.getBytes());
    System.setIn(testIn);
  }

我正在做下一行扫描仪,所以:

command = input.nextLine().toLowerCase().trim();

其中“输入”在这里代表扫描仪对象 但是我仍然遇到此错误,特别是在第一个“正常攻击”传递到system.in

java.util.NoSuchElementException: No line found

在上面那一行。我以为nextline忽略了空格?如果不是我设置的字符串格式错误,则不包含它?

编辑: 在UI.gameLoop()的前几行中,我只初始化了一次扫描程序。

public void gameLoop() throws IOException,JsonSyntaxException {
    input = new Scanner(system.in);
    engine = new GameEngine(path);

解决方法

我以为nextline忽略了空格?

不。根据{{​​3}},它会读取下一个行尾序列(或EOF),然后返回直到(但不包括)行尾序列的所有内容。

如果您得到

java.util.NoSuchElementException: No line found

这意味着Scanner已经到达输入流的末尾,或者(也许)Scanner正在尝试从过早的输入流中读取关闭了代码中的其他地方。

我们可以猜测出真正的问题是什么,但是如果不看>> your javadocs,我们将无法走得更远。


实际上,我只是发现了一个线索:

...我正在用JUnit进行测试...

这可能是您问题的根源。 JVM在其生存期内只能“读取到System.in的末尾”一次。如果您有两个或多个需要执行此操作的JUnit测试,这将很困难,除非您找到一种方法来“模拟” System.in变量。

重组代码可能更简单,以便您从某个流中获取输入作为参数传递给游戏代码。通过重组,您可以更轻松地编写单元测试。

,

没有太多的事情要做,但是我猜您正在创建多个扫描仪,每次要读取一行时就创建一个。由于人类是慢打字员,因此通常可以交互地正常工作,但是当每个扫描程序的预读最终消耗了多行时,此操作将失败。

您可以看到此MCVE中的区别:

import java.util.*;
import java.io.*;

class Foo {
  public static void main(String[] args) throws Exception {
    String newdata = "go forward\ngo left\ntake Pointy Stick\ngo backward\ngo " +
                  "right\nnormal attack\nnormal attack\nquit\n".trim();
    ByteArrayInputStream testIn = new ByteArrayInputStream(newdata.getBytes());
    System.setIn(testIn);

    boolean includeBug = Boolean.valueOf(args[0]);

    if (includeBug) {

      for(int i=0; i<8; i++) {
        Scanner input = new Scanner(System.in);
        System.out.println("Read: " + input.nextLine());
      }

    } else {

      Scanner input = new Scanner(System.in);
      for(int i=0; i<8; i++) {
        System.out.println("Read: " + input.nextLine());
      }

    }
  }
}

includeBug为true时,它将为每行创建一个新的Scanner并崩溃,如您所说。如果为假,它将创建一个扫描仪并正常工作:

$ javac Foo.java
$ java Foo true
Read: go forward
Exception in thread "main" java.util.NoSuchElementException: No line found
        at java.util.Scanner.nextLine(Scanner.java:1540)
        at Foo.main(Foo.java:17)

$ java Foo false
Read: go forward
Read: go left
Read: take Pointy Stick
Read: go backward
(etc)
,

您是否要检查下一行?使用扫描仪,通常要么必须处理异常(不是我真正喜欢的异常),要么必须使用hasNextLine()方法来避免异常。

while (input.hasNextLine()) {
     command = input.nextLine().toLowerCase().trim();
}