Shashi
Shashi

Reputation: 746

how Scanner class works with user defined class as input

recently, i read in a book about passing a user defined class as an input to scanner but it didn't explained much about the logic behind it. here's the program

import java.nio.CharBuffer;
import java.util.Random;
import java.util.Scanner;

class ScannerInputBase implements Readable
{
    private int count;
    Random rand = new Random();
    ScannerInputBase(int count) { this.count = count; }
    public int read(CharBuffer cb)      //read is a method in Readable interface
    {
        if(count-- == 0)
        return -1;

        for(int i=0;i<2;i++)
        { cb.append('a'); }
        return 1;
    }
}

public class ScannerInput {

    public static void main (String args[]) {
        Scanner input = new Scanner(new ScannerInputBase(5));

        while(input.hasNext()) 
        {
            print(input.next()+"-");
        }
    }
}

and it's output is

aaaaaaaaaa- 

i have 2 questions here

  1. how read() function is getting called here?
    i mean i understand it's implicitly geting called somehow but from where it's getting called.

  2. a single hyphen in the output suggests that while loop in main function is iterated only once. but why only once. i was expecting output like aa-aa-aa-aa-aa-

Upvotes: 3

Views: 2227

Answers (2)

Mac
Mac

Reputation: 1495

how read() function is getting called here? i mean i understand it's implicitly geting called somehow but from where it's getting called.

Answer lies in the source code of Scanner class for method next():

public String next() {
    ....
    while (true) {
     .....
     if (needInput)
         readInput();
     ...
    }
}

Which takes us to readInput method which is defined as follows:

private void readInput() {
    ......
     try {
         n = source.read(buf);
     } catch (IOException ioe) {
    .....
     }
    .....
 }

We see that readInput method is calling the read method of source object which is instance of Reader class and is passed as an argument to the Scanner constructor during Scanner's object creation. Now, Since you have passed the object of subclass of Reader as an argument to the Scanner constructor. And also, You have overridden the read(CharBuffer) method witin your class, So the overridden version of read method is being called by the Scanner.readinput method.

A single hyphen in the output suggests that while loop in main function is iterated only once. but why only once. I was expecting output like aa-aa-aa-aa-aa-

Because , there is no whitespace in the string aaaaaaaaaa which is the default delimiter Pattern. Consequenty, all string is read in single iteration. So, hasNext is returning false after first iteration and the while loop terminates.

Note: Always use @Override annotation while overriding a method within subclass.

Upvotes: 2

rocketboy
rocketboy

Reputation: 9741

Scanner class is a wrapper class around streams to read and write data. It has a few overloaded constructors. In your case:

public Scanner(Readable source) {
        this(source, WHITESPACE_PATTERN);
    }

is invoked. Because interface Readable has only one method read(CharBuffer cb), ScannerInputBase is an instaceof Readable, so the Scanner object just invokes the read() method of whatever Readable is passed.

On the second point, look at the documentation of next()

Finds and returns the next complete token from this scanner. A complete token is preceded and followed by input that matches the delimiter pattern. This method may block while waiting for input to scan, even if a previous invocation of hasNext() returned true.

The default pattern used is :

Pattern WHITESPACE_PATTERN = Pattern.compile(
                                                "\\p{javaWhitespace}+");

SO, it your scanner's next() call, reads everything in just one go by making multiple read()calls.

Upvotes: 0

Related Questions