Search code examples
javajava.util.scannerjavadoc

Why doesn't the Javadoc for java.util.Scanner describe under what conditions it blocks?


The Javadoc for java.util.Scanner notes that:

"Both hasNext and next methods may block waiting for further input. Whether a hasNext method blocks has no connection to whether or not its associated next method will block.".

In the descriptions of the various has* and next* methods, it also notes that they "may block while waiting for input to scan". Nowhere however does the page mention under what conditions these methods may block, in spite of this knowledge being a prerequisite for using them.

My question is hence, why doesn't that Javadoc describe under what conditions a Scanner's methods may block? Is there a legitimate reason for omitting this information, or is it just a case of poor documentation?


Solution

  • Now that you've mentioned it, it is pretty vague. Although, explaining it would mean digging into the implementation details.

    The Scanner mainly relies on the underlying stream. Scanner#next() will throw a NoSuchElementException whenever the underlying stream's read() method returns -1 upon reading:

    (implementation summary)

    public void next() {
        if(needInput)
            readInput();
        else
            throwException();
    }
    
    void readInput() {
         int n = 0;
         try {
              n = underlyingStream.read(buf);
         } catch (IOException ioe) {
              lastException = ioe;
              n = -1; //error happened
         }
    
         if (n == -1)
              underlyingStreamClosed = true;
    }
    
    void throwException() {
         if (underlyingStreamClosed)
              throw new NoSuchElementException();
         else
              throw new InputMismatchException();
    }
    

    For example, lets look at InputStream without the scanner. InputStream#read() blocks when it is called, until data comes in. Using an InputStream such as System.in will cause your Scanner to block, since InputStream#read() blocks (the implementation is written in native code, so if you're really interested, you can find the file it's located in and look at the implmenetation yourself). This applies to any stream that extends InputStream, yet doesn't override read() to change it's implementation. For example, ObjectOutputStream, DataOutputStream

    FileInputStream, however, does override read() (also with a native implmenetation). Calling FileInputStream#read() will return -1 when you attempt to read, yet there is nothing there (although the documentation does say this method may block, I have yet to come across the case). This is purely due to the implementation of FileInputStream#read(), which you really shouldn't worry about.

    Long story short: It relies on the underlying stream. Become familiar with your streams, and you'll be set. The way I see it, if you're really worried about which stream blocks or not, look at the implementations (I find that when subclasses don't override the read() method, they tend to block), test them out yourself, or look online. The documentation should likely tell you, although like I said, I have yet to come across a moment when FileInputStream#read() has blocked (could someone help me reproduce the situation, if it does as the documentation says?)