简体   繁体   中英

Cannot close() stream in 'finally' clause, uninitialized variable/unhandled IOException [Java IO]

So I have this method in a class file just trying to write a Book object to aPath (string). However, it gives me 'Unhandled IOException', which I am not sure I understand why as it seems I have a catch clause for my try block.

So to fix this, I tried adding a 'throws' clause to my method, however once I did that, it said that the 'out' variable was not initialized.

Is there any way I can close my stream inside the finally clause?

    public void writeToFile(String aPath) {
    
        ObjectOutputStream out;
        try {
            out = new ObjectOutputStream(new FileOutputStream(aPath));
            
            out.writeObject(this.book);
        }
        catch(IOException e){
            System.out.println("Error writing to file");
            e.printStackTrace();
        }
        finally {
            out.close(); //unhandled IOException error :(
        }
    }

Using try with resources will handle the problem of uninitialized resources:

public void writeToFile(String aPath) {
    try (ObjectOutputStream out = 
             new ObjectOutputStream(new FileOutputStream(aPath))) {
        out.writeObject(this.book);
    }
    catch (IOException e) {
        System.out.println("Error writing to file");
        e.printStackTrace();
    }
}

According to the JLS, an IOException thrown by the writeObject call, OR by the implicit close() of the resource will be caught in that handler.

It is so elegant...


Regarding, your attempt:

I want to know why I cannot use out.close() in finally clause.

Because out has not necessarily been initialized. For example, if the IOException was thrown in new FileOutputStream(...) , out won't have been initialized. To get it to work using an explicit finally , you would need to do something like this:

public void writeToFile(String aPath) {
    ObjectOutputStream out = null;
    try {
        out = new ObjectOutputStream(new FileOutputStream(aPath));
        out.writeObject(this.book);
    }
    catch (IOException e) {
        System.out.println("Error opening or writing to file");
        e.printStackTrace();
    }
    finally {
        if (out != null) {
            try {
                out.close();
            }
            catch (IOException e) {
                System.out.println("Error closing file");
                e.printStackTrace();
            }
        }
    }
}

Since you asked.... the exception handling / squashing is probably a bad idea:

  • The caller gets no indication file write has failed. It will continue executing as if nothing happened.

  • A stacktrace should not normally be written to stdout. If it is relevant, the stacktrace should be logged:

    • If this is an end-user application, showing stacktraces to users is nasty. What they need is an informative error message. Separately logging the exception / stacktrace to a log file may be useful for the sysadmin who installed / configured the software, or the programmer who wrote it.
    • If this is a service, then stuff written to standard output may be lost. Real errors should be logged. Things that are (maybe) due to bad user input should (maybe) not be logged.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM