Java Multiple Scanners

前提是你 提交于 2019-11-26 15:28:41

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.

A first mistake is that this line of code

scanInt.close();

closes the System.in, not just the scanInt object. This means that after the first call to add, the scan object will only consume the input it already has and then you'll receive a NoSuchElementException: Remove this line.

Now, if you replace the last line you have with this

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

you will see that the last input you get before exiting is an empty String. So in the next loop you enter the else statement and your program stops execution. You can fix this problem by adding the following:

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

However, I will agree with Peter that you should not use multiple wrappers. Consider passing the Scanner object as an argument in the Shares class contractor.

Have multiple scanners (on same stream) is a very bad practice, because scanners consume the stream they share.

I've verified while debugging the source code and looking at Scanner class I've found:

  • a reference to the source input stream
  • a internal private buffer used to hold input.

So when a scanner instance consume its stream, basically it just read a bunch of bytes (1024) and the stream's position is moved ahead.

For example when the nextLine() method is invoket, behind the scenes the source.read() copy the result into the private buffer.

Obviously the state of other Scanner becomes corrupted (invalid).

Try to debug the Java source code yourself and/or look at the method Scanner.readInput().

I know this is an older post, but I just wanted to add a short example of what could happen when trying to use two Scanner objects with the same stream:

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
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!