Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Check if a Scanner Was Closed

Tags:

java

I'm having some trouble with two methods I have been trying to write. Both involve using a Scanner to read in a file, where each line is comma delimited. The methods are a part of my FileIO class. In addition to that class, I also have two other classes, Food and FoodArrayList. Food objects contain several pieces of information from food donations (who donated the items, the reason for the donation, etc.). The FoodArrayList class pretty much has the same functionality as an ArrayList, except that I've created it solely for the purpose to store Food objects.

The two methods I am struggling with are as follows:

  1. Reads in the file and simply counts the number of lines in the file. It returns the number of lines. This method is used to determine the size of a FoodArrayList. This is because each line of the file describes a Food object.
  2. Reads in the file and stores the information into a FoodArrayList object. Remember that each comma-delimited line describes a Food object. Hence, this method goes through the file, creates Food objects, and inserts them into a FoodArrayList until it reaches the end of the file.

What I am struggling with is that I close my Scanner in both of the methods. And I've been struggling with how to write an if statement to detect if a Scanner was closed. In both of the methods, I have the following at the very beginning of the method:

    try{
        if(scan.hasNext() == false || scan == null)
            scan = new Scanner(new File(this.getFileName()));
    }
    catch(FileNotFoundException fnfe){
        System.err.println("The " + fileName + " could not be found.");
    }
    catch(IOException ioe){
        ioe.printStackTrace();
    }

This doesn't seem to work though. If I use method #1 first and then later on try to use method #2 (remember that I close the Scanner at the end of each method), the if statement is skipped and scan is never reinstantiated and I am thrown an IllegalStateException.

A very big point that I should have mentioned earlier is this: I want both methods to be reusable. If method #1 goes on until the end of file and I later on use method #2, I would want the Scanner object to be reading from the beginning of the file again. And it seems that the only way to do this is to reinstantiate the Scanner object.

When I first learned about I/O in Java, I remember being told to always make sure to close Scanner objects when you're done using them. That's something that has been ingrained into my brain almost. Regardless, how do I get around this? One thought I had was to set scan to null at the end of both of my methods. Is that even necessary? I've read on other posts in StackOverflow that would lead me to not even closing my Scanner object and just let the garbage collector take care of it.

In addition to all of this, I was also wondering what exactly happens to a Scanner once it is closed and why it can't be reopened. I understand that it has something to do with Streams, but I don't exactly know what those are in the context of Java. I tried looking up the Stream class, but was not able to obtain much of an understanding from it.

Here is the code from both of my methods:

Method #1

public int numberOfLines(){
    try{
        if(scan.hasNext() == false || scan == null)
            scan = new Scanner(new File(this.getFileName()));
    }
    catch(FileNotFoundException fnfe){
        System.err.println("The " + fileName + " could not be found.");
    }
    catch(IOException ioe){
        ioe.printStackTrace();
    }

    int lineCount = 0;
    while(scan.hasNextLine()){
        scan.nextLine();
        lineCount++;
    }
    scan.close();
    return lineCount;
}

Method #2

public void readFile(FoodArrayList fal){
    try{
        if(scan.hasNext() == false || scan == null)
            scan = new Scanner(new File(this.getFileName()));
    }
    catch(FileNotFoundException fnfe){
        System.err.println("The " + fileName + " could not be found.");
    }
    catch(IOException ioe){
        ioe.printStackTrace();
    }

    while(scan.hasNextLine()){
        String stringRead = scan.nextLine();
        StringTokenizer tokens = new StringTokenizer(stringRead,",");
        Food temp = new Food();
        temp.setCorpName(tokens.nextToken());
        temp.getContact().setLast(tokens.nextToken());
        temp.getContact().setFirst(tokens.nextToken());
        temp.setDate(tokens.nextToken());
        temp.setProductCode(tokens.nextToken());
        temp.setDescription(tokens.nextToken());
        temp.setReason(tokens.nextToken());
        String numberString = tokens.nextToken();
        int number = Integer.parseInt(numberString);
        temp.setNumber(number);
        temp.setCoP(tokens.nextToken());
        fal.insert((Food)temp);
    }
    scan.close();
}

I'd like to keep these two methods separate. This is because in my client class, I am performing the following:

    FoodArrayList list;
    FileIO fio = new FileIO();
    int listSize = fio.numberOfLines();     
    list = new FoodArrayList(listSize);     
    fio.readFile(list);

The default constructor of my FileIO class already considers the particular file I am attempting to read. Of course, the overloaded constructor allows one to use a different filename as an input. Any help on this would be appreciated.

like image 266
coolDude Avatar asked Dec 25 '15 01:12

coolDude


People also ask

What if Scanner is not closed?

If you do not close the Scanner then Java will not garbage collect the Scanner object and you will have a memory leak in your program: void close(): closes the Scanner and allows Java to reclaim the Scanner's memory.

What does closing a Scanner do?

When a Scanner is closed, it will close its input source if the source implements the Closeable interface.

When should you close a Scanner?

More specifically, the close() method of the Scanner class is used to close the opened Scanner object. It is recommended to close the Scanner after performing any tasks on the Scanner instance; otherwise, the Scanner will be activated and potentially cause data leaks.


1 Answers

I want both methods to be reusable. If method #1 goes on until the end of file and I later on use method #2, I would want the Scanner object to be reading from the beginning of the file again. And it seems that the only way to do this is to reinstantiate the Scanner object.

It seems like you have your answer here. You want to reinstantiate the Scanner object irrespective of what state one of them may have been in, so just...do that.

At the beginning of your methods, declare and instantiate your Scanner reference. You could also use try-with-resources so that your Scanner is always closed at the end of its run.

public void countLines() {
    try(Scanner scan = new Scanner(new File("file.txt"))) {
        // code
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Even though in reality the work you're doing could be accomplished in the same method, if you insist on performing these operations separately, then initializing two different Scanners is your best option.

like image 187
Makoto Avatar answered Oct 21 '22 13:10

Makoto