Java Multiple Scanners

Ryan Gibson picture Ryan Gibson · Nov 4, 2013 · Viewed 37.9k times · Source

I have a class that creates multiple Integer objects and puts them into a LinkedList as shown below:

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;
    }
}

I have an application that scans for the input "add" from the console and if found, invokes the method add as shown below:

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();
        }
    }
}

The application should allow the user to enter "add" as many times as they wish but the error "no line found" appears after the add method has been invoked.

I'm guessing this is because the Scanner in the method, has not been closed and then reopened when needed. Is this what is wrong with the program and if so, how would I go about fixing it?

Please note, this program is not finished, as I will be adding a selling method that sells these shares. That is why I am using a while loop.

Answer

Peter Lawrey picture Peter Lawrey · Nov 4, 2013

Having multiple wrappers for any stream is a great way to really confuse yourself. I suggest you only ever wrap a stream once unless you really know what you are doing.

The simplest way to do this is to use a singleton in this case as it wraps another singleton (the best is to pass around the Scanner as an argument)

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) {

Im guessing this is because the scanner in the method has not been closed

Once you close a stream it closes the underlying stream and you can't use it again. Only close System.in if you want to prevent it being used again.

how would I go about fixing it?

The best solution is to have all your Scanner use in one place, one method or one class. You have your main() do all the interaction with the user and pass the values to your data structure. Having objects which initialise themselves is a bad practice to get into and if you start doing this, it will plague you for the rest of your development days ;) (Seriously you will see this done again and again and its often a nightmare)


BTW Never exit a program without explanation. Calling System.exit(0); without even an error message is also a nightmare. I once worked on a project which has 260 calls to System.exit() often without an error message, you can imagine how much fun it is to diagnose a server just stopping for no apparent reason.