Question

Hi this is my first question here so if it is for some reason does not obey the rules, turns out to be a duplicate or whatever, please tell me kindly (not that I have any reputation to lose in the first place)

Anyway, I actually have sort of 2 questions about this class StringReader that Java provides. First, what exactly the StringReader.ready() do? Can I use it as a condition in a while loop so that the loop terminates when the string ends? Reading the java doc didn't help much (or maybe I misunderstood what they meant by "Returns True if the next read() is guaranteed not to block for input")

Update:

Sorry apparently I missed the part where it says read() returns -1 when the string ends. Anyway, my question remains for the ready() part. I thought this is supposed to be the one that checks if the string has ended?

Any help would be appreciated, thanks!

Link to the actual source code

The snippet that causes the problem:

while (text.ready()) {

        // Updating stringBuffer, using some sort of 'rolling hash' (or is
        // it
        // indeed rolling hash?)
        stringBuffer.deleteCharAt(0);
        stringBuffer.append((char) next);

        // The next character that follows the sequence of k characters
        next = text.read();

        // store the string form of the buffer to avoid rebuilding the
        // string for the next few checks
        String key = stringBuffer.toString();

        if (hashmap.containsKey(key)) {
            // If the hash map already contain the key, retrieve the array
            asciiArray = hashmap.get(key);
        } else {
            // Else, create a new one
            asciiArray = new int[128];
        }
        System.out.println(next);

        // Error checking on my side only, because some of the text sample I
        // used contains some characters that is outside the 128 ASCII
        // character, for whatever reason
        if (next > 127) {
            continue;
        }

        // Increment the appropriate character in the array
        asciiArray[next]++;
        // Put into the hash map
        hashmap.put(key, asciiArray);

    }
Was it helpful?

Solution

First, what exactly the StringReader.ready() do?

The general contract is that returns true if the next read won't block. In the case of StringReader that is always true.

Can I use it as a condition in a while loop so that the loop terminates when the string ends? Reading the java doc didn't help much (or maybe I misunderstood what they meant by "Returns True if the next read() is guaranteed not to block for input")

No. A simple test reveals that. You should loop until read() returns -1. Note that you must store the result of read() into an int for this to work.

In the while loop that I have constructed, the method StringReader.read() somehow returns -1.

No 'somehow' about it. That's what it's supposed to do.

What does this mean?

It means end of stream. In this case, you've read all the characters out of the StringReader.

Again, the Java doc did not help.

On the contrary. The Javadoc clearly states that read() returns "the character read, or -1 if the end of the stream has been reached".

I am guessing that it means that the string has already terminated

No need to guess about it. That's explicitly what the Javadoc says.

but then that means the ready() method is not doing what it is supposed to do!

No it doesn't. The Javadoc doesn't say that ready() returns false at end of stream. You don't have any warrant for that statement. In this case, it returned true, you called read(), and it didn't block. Contract satisfied.

OTHER TIPS

If you look at the source code of StringReader.ready() method you can find the answer. StringReader is a decorator class written to read Strings using a reader. You can only create a StringReader instance by passing a String argument in.

The StringReader.ready() will always return true and only throw an IOException if the String passed while instantiating is null

 public boolean ready() throws IOException {
     synchronized (lock) {
        ensureOpen();
        return true;
     }
 }

 /** Check to make sure that the stream has not been closed */
 private void ensureOpen() throws IOException {
     if (str == null)
        throw new IOException("Stream closed");
 }

To help you better understand the concept, let's say your StringReader is reading a sequences of characters from a slooooow TCP connection, at a rate of one character per-second...

If you then call StringReader.read() in a while loop, then each time read() will wait for 1 second before returning a character. This can be a problem if you don't want your code to hang there waiting for characters to come in. That's when StringReader.ready() becomes handy. If it returns false, then that means a call to read() may cause the code to block (waiting), whereas if ready() returns true it means a call to read() will immediately returns a value (character or -1) without blocking/waiting.

Now let's say all the characters have already been transferred through the connection, and the connection is therefore closed, then ready() will still return true because it knows it doesn't need to wait for the next character (since there is none). Now when you call read(), it will also immediately returns, but this time with a -1, meaning no more characters.

Now let's get back to your code. For what you are trying to achieve, you don't need to use ready(). Instead, the first line of your code should be changed to:

int ch;

while (true)
{
    ch = text.read();
    if (ch < 0) break;

    ...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top