zeroTAG
zeroTAG

Reputation: 65

BufferedReader not null yet .readLine() returning null

I have a weird problem, where my code seems fine (for me at least), yet on the debugger and actual result is always wrong.

Firstly the code:

private void updateRegistry( String filename ){
    BufferedReader database = Init.MANAGER.readFile( Path.getDB(), filename );

    REGISTRY.clear();

    long maxLines = database.lines().count();
    for (int i = 0; i < maxLines; i++) {
        try {
            String currentLine = database.readLine();
            Registry regAdd = new Entry( currentLine );
            REGISTRY.add( regAdd );
        } catch( Exception e ) {
            System.err.println( ERROR.getStackTrace( e ) );
        }
    }
}

So, all currentLine variables in the loop always returns null.

Being the REGISTRY a constant on the class which is a LinkedList.
And ERROR another constant to report errors, which is not relevant.

I'm aware of .readLine() that reads a line per method call, making each call the next line to be read.

Also, by using the debugger, I can confirm the data is being recovered in the BufferedReader variable.

Yet the .readLine() method returns null. I have no idea what the problem is.

My only guess is the .lines() that I used to count them. Does that make the stream null? If this is the problem, how can I correct it, since I need the line count.

What am I doing wrong? I debugged this a hundred times, nothing I do gives me the data.

EDIT:

For future reference, I used the example of this other post, which I prefer more than the while loop. After removing the .lines() variable and the loop

private void updateRegistry( String filename ){
    BufferedReader database = Init.MANAGER.readFile( Path.getDB(), filename );

    REGISTRY.clear();

    try {
        for ( String currentLine = database.readLine(); currentLine != null; currentLine = database.readLine() ) {
            Registry regAdd = new Registry( currentLine );
            REGISTRY.add( regAdd );
        }
    } catch ( Exception e ){
        System.err.println( ERROR.getStackTrace( e ) );
    }
}

Post Link

Thanks for the help, now I can finish my work assignment faster! xD

As, now my best friend, Holger mentioned, gonna use the stream loop directly, which makes it even neater.

database.lines().forEach(currentLine -> REGISTRY.add(new Entry(currentLine)));

And an one liner! Beautiful! Gonna dwelve on the stream world after this.

Upvotes: 1

Views: 1252

Answers (2)

Holger
Holger

Reputation: 298163

See BufferedReader.lines():

After execution of the terminal stream operation there are no guarantees that the reader will be at a specific position from which to read the next character or line.

Thus, after invoking long maxLines = database.lines().count();, there is no guaranty that you can read any lines from the same reader afterwards. In typical implementations, this operation consumes all lines.

If you can’t re-acquire an equivalent reader, but really need the count beforehand, the only option is to buffer them, e.g. to collect all lines into a List like

List<String> list=database.lines().collect(Collectors.toList());

to get the size and the contents.


If you don’t need the count beforehand, you can replace the counting operation with your actual operation:

database.lines().forEach(currentLine -> REGISTRY.add(new Entry(currentLine));

As danmec has pointed out, even without the stream API, you don’t need the count beforehand, when all you want to do with it, is performing the iteration.

Upvotes: 3

mecsco
mecsco

Reputation: 2250

BufferedReader.lines() is a new method in Java 8 which I'm not too familiar with. However, since you just want to process each line in turn, you would typically use something like this:

String currentLine = null;
while ((currentLine = database.readLine()) != null) {
    // do processing
}

Upvotes: 3

Related Questions