16

我有一个创建多个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循环的原因。

4

3 回答 3

17

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

最简单的方法是在这种情况下使用单例,因为它包装了另一个单例(最好的方法是将 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 次调用,通常没有错误消息,您可以想象诊断服务器无缘无故停止是多么有趣。

于 2013-11-04T11:19:23.307 回答
11

第一个错误是这行代码

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 类承包商。

于 2013-11-04T11:45:04.507 回答
3

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

我在调试Scanner类源代码时验证了它,我发现:

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

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

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

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

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

于 2017-04-07T16:29:39.173 回答