【问题标题】:Java Multiple ScannersJava 多扫描仪
【发布时间】:2013-11-15 00:04:54
【问题描述】:

我有一个类创建多个Integer 对象并将它们放入LinkedList 中,如下所示:

public class Shares<E> implements Queue<E> {
    protected LinkedList<E> L;

    public Shares() {
        L = new LinkedList<E>();
    }

    public boolean add(E price) {
        System.out.println("How many of these shares would you like?");
        Scanner scanInt;
        scanInt = new Scanner(System.in);
        Integer noShares = scanInt.nextInt();
        for (int i = 0; i < noShares; i++) {
            L.addLast(price);
        }
        scanInt.close();

        return true;
    }
}

我有一个应用程序从控制台扫描输入“add”,如果找到,调用方法add,如下所示:

public class Application {
    private static Scanner scan;

    public static <E> void main(String[] args) {
        Queue<Integer> S = new Shares<Integer>();
        scan = new Scanner(System.in);
        System.out.println("Please type add");
        String sentence = scan.nextLine();
        while (sentence.equals("quit") == false) {
            if (sentence.equals("add")) {

                System.out
                    .println("What price would you like to buy your shares at?");

                S.add((Integer) scan.nextInt());

            } else
                System.exit(0);

            sentence = scan.nextLine();
        }
    }
}

应用程序应允许用户根据需要多次输入“add”,但在调用add 方法后会出现错误“no line found”。

我猜这是因为方法中的Scanner 尚未关闭,然后在需要时重新打开。这是程序出了什么问题,如果是,我将如何解决它?

请注意,此程序尚未完成,因为我将添加出售这些股票的出售方法。这就是我使用 while 循环的原因。

【问题讨论】:

  • 像您在 S.add 中那样调用扫描仪会不会有问题?

标签: java java.util.scanner


【解决方案1】:

为任何流拥有多个包装器是真正让自己感到困惑的好方法。我建议你只包装一次流,除非你真的知道自己在做什么。

在这种情况下,最简单的方法是使用一个单例,因为它包装了另一个单例(最好的方法是将 Scanner 作为参数传递)

public class Application { 
    // use this Scanner in all you other code, don't create another one.
    static final Scanner scan = new Scanner(System.in);

    public static <E> void main(String[] args) {

我猜这是因为方法中的扫描仪没有关闭

一旦你关闭了一个流,它就会关闭底层的流并且你不能再次使用它。仅当您想防止再次使用 System.in 时才关闭它。

我将如何解决它?

最好的解决方案是将您的所有 Scanner 使用在一个地方、一种方法或一个类中。您让 main() 与用户进行所有交互并将值传递给您的数据结构。拥有自己初始化的对象是一种不好的做法,如果你开始这样做,它会在你剩下的开发日里困扰你;)(说真的,你会一次又一次地看到这样做,这通常是一场噩梦)


顺便说一句,不要在没有解释的情况下退出程序。在没有错误消息的情况下调用System.exit(0); 也是一场噩梦。我曾经参与过一个项目,该项目对 System.exit() 进行了 260 次调用,通常没有错误消息,您可以想象诊断服务器无故停止是多么有趣。

【讨论】:

    【解决方案2】:

    第一个错误是这行代码

    scanInt.close();
    

    关闭 System.in,而不仅仅是 scanInt 对象。这意味着在第一次调用 add 之后,扫描对象将只使用它已经拥有的输入,然后您将收到 NoSuchElementException: Remove this line.

    现在,如果你用这个替换最后一行

    sentence = scan.nextLine();
    System.out.println("sentence: \"" + sentence + "\"");
    

    您会看到退出前的最后一个输入是一个空字符串。因此,在下一个循环中,您输入 else 语句,您的程序将停止执行。您可以通过添加以下内容来解决此问题:

    scan.nextLine(); // consume the first always empty String...
    System.out.println("Please type add");
    sentence = scan.nextLine(); // and then get the actual value
    

    但是,我同意 Peter 的观点,即您不应该使用多个包装器。考虑将 Scanner 对象作为参数传递给 Shares 类承包商。

    【讨论】:

    • "...关闭 System.in,而不仅仅是...",这只是为我解决了另一个问题。谢谢。
    【解决方案3】:

    拥有多个扫描器(在同一个流上)是一种非常糟糕的做法,因为扫描器会消耗它们共享的流。

    我在调试Scanner类源代码的时候验证过,发现:

    • 对源输入流的引用
    • 用于保存输入的内部私有缓冲区。

    所以当扫描器实例消耗它的流时,基本上它只是读取一堆字节(1024)并且流的位置向前移动。

    例如,当nextLine() 方法被调用时,source.read() 在后台将结果复制到私有缓冲区中。

    显然其他 Scanner 的状态已损坏(无效)。

    尝试自己调试 Java 源代码和/或查看方法 Scanner.readInput()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多