1a1a11a
1a1a11a

Reputation: 1267

how to organize code to close file effectively in java

I am trying to read something from a file in Java and then close it. But I don't know where to put the close method.

    try {
        Scanner scanner = new Scanner(new FileInputStream("data"));
        while (scanner.hasNext()){
            String line = scanner.nextLine().trim();
            set.add(line);
        }
        //scanner.close();
    } catch (FileNotFoundException e) {
        System.out.println("data is not found");
        e.printStackTrace();
    } finally{
        //scanner.close();
    }

As you can see in the code, there are two places I could possibly put the close method, one is inside try, one is inside finally. If I put it in the try clause, it something fails after that, the scanner cannot be closed; however, if I put it in the finally clause, I need to declare the scanner before try-clause, in this way, if the file open fails, the close method in finally does not make sense, because scanner is still null.

I know there must be something wrong in these thoughts, could someone point out?

Upvotes: 0

Views: 80

Answers (5)

Gene
Gene

Reputation: 46960

The normal idiom (I'm surprised no one has shown it yet) is to declare the variable before the try with no initialization, then set it inside the try. To get what you want, you'd say...

Scanner scanner;
try {
    scanner = new Scanner(new FileInputStream("data"));
    while (scanner.hasNext()){
        String line = scanner.nextLine().trim();
        set.add(line);
    }
} catch (FileNotFoundException e) {
    System.out.println("data is not found");
    e.printStackTrace();
} finally{
    scanner.close();
}

However, this is not the right way to go. It's best if the try/catch should include only the code that can generate the not found exception. That's the file open. If you need (not done below), refactor the try/catch into its own private method.

FileInputStream fis;
try {
  fis = new FileInputStream("data")
} catch (FileNotFoundException e) {
  System.out.println("data is not found");
  e.printStackTrace();
  return;  // Or you can throw another exception here...
}
// Properly used scanners don't raise exceptions, so
// putting this in a try catch block is poor practice.
// (IOExceptions of the stream are caught by the scanner
// and treated as end-of-input.)
Scanner scanner = new Scanner(fis);
while (scanner.hasNextLine() {
  String line = scanner.nextLine().trim();
  set.add(line);
}
scanner.close();

Upvotes: 0

user207421
user207421

Reputation: 310884

The correct way to use try-with-resources for this is to open the file separately from the scanner:

try (FileInputStream fis = new FileInputStream(...);
    Scanner scanner = new Scanner(fis))
{
    // ...
}
catch ...

Then both streams will be closed if they exist.

Upvotes: 1

1337joe
1337joe

Reputation: 2367

If you're using Java 8 I'd highly recommend using try-with-resources:

try (Scanner scanner = new Scanner(new FileInputStream("data"))) {
    while (scanner.hasNext()) {
        String line = scanner.nextLine().trim();
        set.add(line);
    }
} catch (FileNotFoundException e) {
    System.out.println("data is not found");
    e.printStackTrace();
}

With this pattern java implicitly adds a finally block to call scanner.close().

If you can't take advantage of the features of Java 8 then your best option is to declare scanner before the try block and check for null when closing it in the finally:

Scanner scanner = null;
try {
    scanner = new Scanner(new FileInputStream("data"));
    while (scanner.hasNext()) {
        String line = scanner.nextLine().trim();
        set.add(line);
    }
} catch (FileNotFoundException e) {
    System.out.println("data is not found");
    e.printStackTrace();
} finally {
    if (scanner != null) {
        scanner.close();
    }
}

Upvotes: 2

Eric Martinez
Eric Martinez

Reputation: 31777

Try this

Scanner scanner = null;
try {
    scanner = new Scanner(new FileInputStream("data"));
    while (scanner.hasNext()){
        String line = scanner.nextLine().trim();
        set.add(line);
    }
    //scanner.close();
} catch (FileNotFoundException e) {
    System.out.println("data is not found");
    e.printStackTrace();
} finally{
    if(scanner != null)
         scanner.close();
}

Upvotes: 1

Matt C
Matt C

Reputation: 4555

You could use this method which follows the iterator pattern of while(hasNext()) -> read -> close.

    try {
            Scanner scanner = new Scanner(new FileInputStream("data"));
            while (scanner.hasNext()){
                String line = scanner.nextLine().trim();
                set.add(line);
            }
            scanner.close();
        } catch (FileNotFoundException e) {
            System.out.println("data is not found");
            e.printStackTrace();
        } finally{
        }

This way, the scanner is only not null if the file was opened successfully, and then it is closed after the objects were read. There should not be an exception there, and if you think there might be, you can add in a nested try block to catch a reading exception. Then close the scanner in the first try block.

Upvotes: -1

Related Questions