Java多个扫描仪

时间:2013-11-04 11:14:37

标签: java java.util.scanner

我有一个创建多个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方法后出现错误“找不到行”。

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

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

4 个答案:

答案 0 :(得分:13)

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

最简单的方法是在这种情况下使用单例,因为它包装了另一个单例(最好是将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。

  

我该如何解决它?

最佳解决方案是让所有扫描仪在一个地方,一个方法或一个类中使用。您让main()完成与用户的所有交互,并将值传递给您的数据结构。拥有自我初始化的对象是一个不好的做法,如果你开始这样做,它将困扰你的余下你的开发日;)(严重的是你会看到这一次又一次地完成,它往往是一场噩梦)


BTW切勿在没有说明的情况下退出程序。在没有错误消息的情况下调用System.exit(0);也是一场噩梦。我曾经做过一个项目,它有260次调用System.exit(),通常没有错误信息,你可以想象诊断一台服务器只是停下来没有明显的原因是多么有趣。

答案 1 :(得分:6)

第一个错误是这行代码

scanInt.close();

关闭System.in,而不仅仅是scanInt对象。这意味着在第一次调用add之后,scan对象只会消耗它已有的输入,然后你会收到NoSuchElementException:删除这一行。

现在,如果您使用此

替换最后一行
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

但是,我同意彼得你不应该使用多个包装器。考虑将Scanner对象作为Shares类承包商中的参数传递。

答案 2 :(得分:0)

有多个扫描程序(在同一个数据流上)是一种非常糟糕的做法,因为扫描程序会使用它们共享的流。

我在调试源代码时已经验证并查看了我发现的Scanner类:

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

因此,当扫描程序实例使用其流时,基本上它只读取一堆字节(1024)并且流的位置向前移动。

例如,当nextLine()方法是invoket时,source.read()将结果复制到私有缓冲区中。

显然,其他扫描仪的状态已损坏(无效)。

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

答案 3 :(得分:0)

我知道这是一篇较旧的文章,但是我只想添加一个简短的示例,说明尝试在同一流中使用两个Scanner对象时可能发生的情况:

public static void main (String [] args) {
    Scanner scan = new Scanner(System.in);
    Scanner scan2 = new Scanner(System.in);

    System.out.println("First: "+scan.nextLine());
    System.out.println("Second: "+scan2.nextLine());

    scan.close(); // Only one scanner is closed, but...

    System.out.println("Third: "+scan2.nextLine()); // Trying to use the other scanner will throw an exception
}