【问题标题】:Java Scanner does not wait for inputJava Scanner 不等待输入
【发布时间】:2012-11-14 07:50:07
【问题描述】:

我这里有两个代码块。一个扫描仪正确地等待用户输入,而另一个扫描仪直接吹过它并调用nextInt(),它返回一个NoSuchElementException。这是有效的块:

public void startGame() {
   out.println("Player1: 1 for dumb player, 2 for smart player, 3 for human player.");
   Scanner scan = new Scanner(System.in);
   p = scan.nextInt();

   if (p == 1)
        p1 = new DumbPlayer("ONE");
   if (p == 2)
        p1 = new SmartPlayer("ONE");
   else 
       p1 = new HumanPlayer("ONE");

   out.println("Player2: 1 for dumb player, 2 for smart player, 3 for human player.");
   p = scan.nextInt();

   if (p == 1)
        p2 = new DumbPlayer("TWO");
   if (p == 2)
        p2 = new SmartPlayer("TWO");
   else 
        p2 = new HumanPlayer("TWO");

   scan.close();

这是没有的块:

public int findBestMove(Set<Integer> moves, Board b) {

    Set<Integer> set = new HashSet<Integer>();

    out.println("Player " +name+ ", select a column from 1-7: ");
    Scanner scan = new Scanner(System.in);  <--here it should wait for input, but does not!
    int move = scan.nextInt();   <-- NoSuchElementException
    scan.close();

    for (int x = 1; x <= 7; x++) {
        set.add(move);
        move += 7;
    }
    ....etc

这两个都是独立的类,并且是从另一个类的主方法调用的。基本上main() 调用startGame(),后者又调用某个Player 类的findBestMove() 方法......这是非工作代码所在的位置。程序中是否存在不适合接受输入的情况?我的印象是,只要我想要用户输入,我就可以使用这种方法。谢谢!

【问题讨论】:

  • 我在findBestMove 中看到您执行scan.close() 也会关闭源流 - 您是否在startGame() 中执行相同操作,在您的etc 之后某处?
  • 此问题中讨论的类似问题,不确定是否应作为重复关闭:stackoverflow.com/questions/7056749/…
  • @Dennis 我在发帖之前查看过,我认为我的问题不相关但可能是错误的。
  • @Houdini 那么,这可能是 Denis 提到的问题之外的第二个问题。不要这样做——InputStream 实现了Closeable 接口,在这种情况下Scanner.close() 也将关闭System.indocs.oracle.com/javase/7/docs/api/java/util/Scanner.html
  • 你在任何地方都有一个全局try...catch 块吗?因为关闭扫描仪并打开新的扫描仪会在下次读取时给我一个NoSuchElementException,因为标准输入已关闭。

标签: java user-input java.util.scanner


【解决方案1】:

nextInt() 不会丢弃流中的\n,因此下一次调用什么也找不到。您必须使用 Scanner.skip("\n")Scanner.nextLine() 手动跳过它

编辑在弄清楚“跳过readInt()”意味着代码引发了异常之后。在@Andreas 的帮助下,这是一个替代解决方案。在 java6 中,添加了一个新类 Console,以便为标准输入提供更好的接口。它返回一个不关心你关闭它的阅读器。所以下面的 sn-p 工作得很好:

    Scanner fi = new Scanner(System.console().reader());
    System.out.println(fi.nextInt());
    fi.close();

    fi = new Scanner(System.console().reader());
    System.out.println(fi.nextInt());
    fi.close();

【讨论】:

  • @Houdini:在调用nextInt()之前
  • 为什么我必须在第二种情况下而不是第一种情况下这样做?
  • 我试过了,但它要么说找不到行,要么在"\n"的情况下说at java.util.Scanner.skip(Unknown Source)
  • @Houdini:查看我对您问题的替代解决方案的编辑。
  • 由于某种原因,System.console() 返回 null,所以当我尝试调用 console.reader() 时,它给了我一个 NullPointerException
【解决方案2】:

根据java.util.Scanner javadoc,如果此流实现Closeable 接口,Scanner.close() 将关闭关联的流。 java.lang.System.in 是一个InputStream,它实现了Closeable 接口。因此,在与System.in 关联的Scanner 上调用Scanner.close() 后,System.in 流将关闭且不再可用。

以下 SSCCE 适合我。我从问题中删除了一些与实际问题无关的代码。请注意,使用这种方法,虽然它有效,但 Eclipse 会向我发出警告 "Resource leak: 'scan' is never closed",因此更好的解决方案是仅使用一个 Scanner 实例。

package com.example;

import java.util.Scanner;
import java.util.Set;
import static java.lang.System.out;

public class ScannerTest {
    int p = 0;
    String name = "Test";

    public void startGame() {
        out.println("Player1: 1 for dumb player, 2 for smart player, 3 for human player.");
        Scanner scan = new Scanner(System.in);
        p = scan.nextInt();

        out.println("Result1: " + p);

        out.println("Player2: 1 for dumb player, 2 for smart player, 3 for human player.");
        p = scan.nextInt();

        out.println("Result2: " + p);

        // scan.close();   // Do not close the Scanner to leave System.in open
    }

    public int findBestMove(Set<Integer> moves, Object /*Board*/ b) {
        out.println("Player " +name+ ", select a column from 1-7: ");
        Scanner scan = new Scanner(System.in);
        int move = scan.nextInt();
        // scan.close();   // Do not close the Scanner to leave System.in open

        out.println("Move: " + move);

        return 0;
    }

    public void run() {
        startGame();
        findBestMove(null, null);
    }

    public static void main(String[] args) {
        ScannerTest st = new ScannerTest();
        st.run();
    }
}

【讨论】:

  • 非常感谢,其他人也提到了这一点,但他们没有说不要close()那个已经在工作的班级!这对我来说太奇怪了,当我声明新的 Scanner 时,我不打开输入流备份吗?哦,好吧...现在开始工作,谢谢!
  • 你可能知道这一点,但对于其他人可能正在阅读你可以做一个import static java.lang.System.*,这也将允许使用out.println()
  • 谢谢 :) 我已经更新了示例代码。无论如何,在使用静态导入时,请务必查看 Static Import 文档。通常我会避免通配符导入。而且我不确定我是否更喜欢静态导入System.out 而不是显式注意System.out,尤其是因为java.lang.* 无论如何都是隐式导入的。另见stackoverflow.com/questions/2504078/…,尤其是Stephen C的答案。
【解决方案3】:

尝试使用scan.reset(); 而不是scan.close()scan.close() 会像 Denis Tulskiy 所说的那样抛出 NoSuchElementException。

【讨论】:

  • scan.close()之前抛出异常。
  • 当然可以。我会添加细节。通过说 scan.close() 我的意思是使用它。实际上,当它扫描下一个发现扫描仪已关闭的项目时,它会抛出此错误。这是我调试发现的。
  • 即使我让扫描仪保持打开状态,我也会得到相同的结果。
【解决方案4】:

我只花了大约 15 分钟来解决这个问题,我的问题与上述所有问题都不同。

代码很好,但我正在使用 Sublime Text 并在 Windows 上的 sublime 文本内的终端模拟器中运行它。这阻止了扫描仪实际上允许我尝试输入内容。

我使用 cmd 运行该应用程序,它运行良好。我希望这对某人有所帮助。

【讨论】:

    猜你喜欢
    • 2014-06-20
    • 2013-01-13
    • 2021-01-19
    • 1970-01-01
    • 2013-04-04
    • 2021-03-05
    • 2011-12-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多